Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
325 lines
9.9 KiB
Python
325 lines
9.9 KiB
Python
"""
|
|
高级示例 - 展示 Web Search Agent 的各种用法
|
|
"""
|
|
|
|
import asyncio
|
|
import json
|
|
from typing import List, Dict, Any
|
|
from agent import WebSearchAgent, is_failure_answer
|
|
from config import Config
|
|
import logging
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class AdvancedWebSearchAgent(WebSearchAgent):
|
|
"""
|
|
高级 Web Search Agent - 扩展功能
|
|
"""
|
|
|
|
def batch_search(self, questions: List[str]) -> List[Dict[str, str]]:
|
|
"""
|
|
批量搜索多个问题
|
|
|
|
Args:
|
|
questions: 问题列表
|
|
|
|
Returns:
|
|
答案列表
|
|
"""
|
|
results = []
|
|
for i, question in enumerate(questions, 1):
|
|
logger.info(f"处理问题 {i}/{len(questions)}: {question}")
|
|
try:
|
|
answer = self.search_and_answer(question)
|
|
# search_and_answer 内部已捕获异常并返回错误字符串(见 agent.py),
|
|
# 因此下面的 except 通常不会触发。用统一的 is_failure_answer 判定状态,
|
|
# 覆盖“出现错误 / 超过最大迭代次数 / 无法获取足够信息”所有失败兜底,
|
|
# 避免把失败的搜索错误地标记为 success。
|
|
status = "error" if is_failure_answer(answer) else "success"
|
|
results.append({
|
|
"question": question,
|
|
"answer": answer,
|
|
"status": status
|
|
})
|
|
except Exception as e:
|
|
results.append({
|
|
"question": question,
|
|
"answer": str(e),
|
|
"status": "error"
|
|
})
|
|
# 清空历史,避免上下文混淆
|
|
self.clear_history()
|
|
return results
|
|
|
|
def search_with_context(self, question: str, context: str) -> str:
|
|
"""
|
|
带上下文的搜索
|
|
|
|
Args:
|
|
question: 用户问题
|
|
context: 额外的上下文信息
|
|
|
|
Returns:
|
|
答案
|
|
"""
|
|
# 构建带上下文的问题
|
|
contextualized_question = f"""
|
|
背景信息:{context}
|
|
|
|
基于上述背景,请回答以下问题:
|
|
{question}
|
|
"""
|
|
return self.search_and_answer(contextualized_question)
|
|
|
|
def comparative_search(self, items: List[str], aspect: str) -> str:
|
|
"""
|
|
比较搜索 - 搜索并比较多个项目
|
|
|
|
Args:
|
|
items: 要比较的项目列表
|
|
aspect: 比较的方面
|
|
|
|
Returns:
|
|
比较结果
|
|
"""
|
|
# 构建比较问题
|
|
items_str = "、".join(items)
|
|
question = f"请搜索并比较 {items_str} 在 {aspect} 方面的差异和优劣"
|
|
|
|
return self.search_and_answer(question)
|
|
|
|
def fact_check(self, statement: str) -> Dict[str, Any]:
|
|
"""
|
|
事实核查 - 验证陈述的真实性
|
|
|
|
Args:
|
|
statement: 需要验证的陈述
|
|
|
|
Returns:
|
|
验证结果
|
|
"""
|
|
question = f"""
|
|
请验证以下陈述的真实性:
|
|
"{statement}"
|
|
|
|
请严格按以下格式作答:
|
|
- 第一行只输出判定结论,三选一:真 / 假 / 部分真实
|
|
- 之后另起一行给出相关事实、证据与信息来源
|
|
"""
|
|
answer = self.search_and_answer(question)
|
|
|
|
# 解析判定:模型被要求首行只输出“真/假/部分真实”。
|
|
# 按“部分真实 -> 假 -> 真”的优先级匹配,避免“真”字出现在
|
|
# “部分真实/不真实”里而被误判为真(原实现 `"真" in answer[:100]` 的缺陷)。
|
|
first_line = next((ln.strip() for ln in answer.splitlines() if ln.strip()), "")
|
|
if "部分真实" in first_line or "部分正确" in first_line:
|
|
is_true = False
|
|
elif any(neg in first_line for neg in ("假", "不真实", "不属实", "不准确", "不正确", "错误")):
|
|
is_true = False
|
|
else:
|
|
is_true = "真" in first_line or "属实" in first_line or "正确" in first_line
|
|
return {
|
|
"statement": statement,
|
|
"is_true": is_true,
|
|
"explanation": answer
|
|
}
|
|
|
|
|
|
def example_basic_search():
|
|
"""基础搜索示例"""
|
|
print("\n" + "="*60)
|
|
print("📌 示例 1: 基础搜索")
|
|
print("="*60)
|
|
|
|
agent = WebSearchAgent(Config.get_api_key())
|
|
|
|
questions = [
|
|
"OpenAI 最新发布的 GPT 模型有什么特点?",
|
|
"如何学习机器学习?推荐一些资源",
|
|
]
|
|
|
|
for q in questions:
|
|
print(f"\n问题: {q}")
|
|
print("-"*40)
|
|
answer = agent.search_and_answer(q)
|
|
print(f"答案: {answer}")
|
|
|
|
|
|
def example_batch_search():
|
|
"""批量搜索示例"""
|
|
print("\n" + "="*60)
|
|
print("📌 示例 2: 批量搜索")
|
|
print("="*60)
|
|
|
|
agent = AdvancedWebSearchAgent(Config.get_api_key())
|
|
|
|
questions = [
|
|
"React 和 Vue 的主要区别是什么?",
|
|
"Python 最适合做什么类型的项目?",
|
|
"如何开始学习人工智能?",
|
|
]
|
|
|
|
results = agent.batch_search(questions)
|
|
|
|
for result in results:
|
|
print(f"\n问题: {result['question']}")
|
|
print(f"状态: {result['status']}")
|
|
print(f"答案: {result['answer'][:200]}...") # 只显示前200字符
|
|
|
|
|
|
def example_contextual_search():
|
|
"""带上下文的搜索示例"""
|
|
print("\n" + "="*60)
|
|
print("📌 示例 3: 带上下文的搜索")
|
|
print("="*60)
|
|
|
|
agent = AdvancedWebSearchAgent(Config.get_api_key())
|
|
|
|
context = "我是一个刚开始学习编程的大学生,主要对 Web 开发感兴趣"
|
|
question = "我应该先学习哪种编程语言?"
|
|
|
|
print(f"上下文: {context}")
|
|
print(f"问题: {question}")
|
|
print("-"*40)
|
|
|
|
answer = agent.search_with_context(question, context)
|
|
print(f"答案: {answer}")
|
|
|
|
|
|
def example_comparative_search():
|
|
"""比较搜索示例"""
|
|
print("\n" + "="*60)
|
|
print("📌 示例 4: 比较搜索")
|
|
print("="*60)
|
|
|
|
agent = AdvancedWebSearchAgent(Config.get_api_key())
|
|
|
|
# 比较不同的技术框架
|
|
items = ["TensorFlow", "PyTorch", "JAX"]
|
|
aspect = "性能和易用性"
|
|
|
|
print(f"比较项目: {', '.join(items)}")
|
|
print(f"比较方面: {aspect}")
|
|
print("-"*40)
|
|
|
|
result = agent.comparative_search(items, aspect)
|
|
print(f"比较结果:\n{result}")
|
|
|
|
|
|
def example_fact_check():
|
|
"""事实核查示例"""
|
|
print("\n" + "="*60)
|
|
print("📌 示例 5: 事实核查")
|
|
print("="*60)
|
|
|
|
agent = AdvancedWebSearchAgent(Config.get_api_key())
|
|
|
|
statements = [
|
|
"Python 是世界上最流行的编程语言",
|
|
"量子计算机已经可以破解所有现代加密算法",
|
|
"GPT-4 有 1.76 万亿个参数",
|
|
]
|
|
|
|
for statement in statements:
|
|
print(f"\n陈述: {statement}")
|
|
result = agent.fact_check(statement)
|
|
print(f"真实性: {'✅ 真' if result['is_true'] else '❌ 假/存疑'}")
|
|
print(f"解释: {result['explanation'][:200]}...")
|
|
|
|
|
|
def example_research_assistant():
|
|
"""研究助手示例 - 深度研究某个主题"""
|
|
print("\n" + "="*60)
|
|
print("📌 示例 6: 研究助手 - 深度研究")
|
|
print("="*60)
|
|
|
|
agent = AdvancedWebSearchAgent(Config.get_api_key())
|
|
|
|
topic = "大语言模型的发展历程"
|
|
|
|
# 构建研究问题序列
|
|
research_questions = [
|
|
f"什么是{topic}?请提供详细定义",
|
|
f"{topic}的关键里程碑和重要事件有哪些?",
|
|
f"{topic}面临的主要挑战是什么?",
|
|
f"{topic}的未来发展趋势如何?",
|
|
]
|
|
|
|
print(f"研究主题: {topic}")
|
|
print("="*60)
|
|
|
|
research_report = []
|
|
for i, q in enumerate(research_questions, 1):
|
|
print(f"\n研究问题 {i}: {q}")
|
|
print("-"*40)
|
|
answer = agent.search_and_answer(q)
|
|
research_report.append({
|
|
"section": i,
|
|
"question": q,
|
|
"findings": answer
|
|
})
|
|
print(f"发现: {answer[:300]}...")
|
|
agent.clear_history() # 清空历史,确保每个问题独立
|
|
|
|
# 保存研究报告
|
|
with open("research_report.json", "w", encoding="utf-8") as f:
|
|
json.dump(research_report, f, ensure_ascii=False, indent=2)
|
|
print(f"\n✅ 研究报告已保存到 research_report.json")
|
|
|
|
|
|
def main():
|
|
"""运行所有示例"""
|
|
|
|
if not Config.validate():
|
|
print("请先设置 KIMI_API_KEY 环境变量")
|
|
return
|
|
|
|
examples = [
|
|
("基础搜索", example_basic_search),
|
|
("批量搜索", example_batch_search),
|
|
("带上下文搜索", example_contextual_search),
|
|
("比较搜索", example_comparative_search),
|
|
("事实核查", example_fact_check),
|
|
("研究助手", example_research_assistant),
|
|
]
|
|
|
|
print("\n" + "="*60)
|
|
print("🎯 Kimi Web Search Agent - 高级示例")
|
|
print("="*60)
|
|
print("\n选择要运行的示例:")
|
|
|
|
for i, (name, _) in enumerate(examples, 1):
|
|
print(f"{i}. {name}")
|
|
print(f"{len(examples) + 1}. 运行所有示例")
|
|
print("0. 退出")
|
|
|
|
try:
|
|
choice = input("\n请输入选项 (0-7): ").strip()
|
|
choice = int(choice)
|
|
|
|
if choice == 0:
|
|
print("退出程序")
|
|
return
|
|
elif 1 <= choice <= len(examples):
|
|
examples[choice - 1][1]()
|
|
elif choice == len(examples) + 1:
|
|
for name, func in examples:
|
|
try:
|
|
func()
|
|
except Exception as e:
|
|
logger.error(f"运行 {name} 时出错: {str(e)}")
|
|
else:
|
|
print("无效的选项")
|
|
except ValueError:
|
|
print("请输入有效的数字")
|
|
except KeyboardInterrupt:
|
|
print("\n程序被中断")
|
|
except Exception as e:
|
|
logger.error(f"运行示例时出错: {str(e)}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|