LangChain-Chatchat 开发与应用(六) Agent能力揭秘-让大模型不仅能聊天还能干活
Agent 能力揭秘:让大模型不仅能"聊天",还能"干活"
标签:Agent | Function Call | 工具调用 | 自主决策 | ReAct
一、从一个"不够用"的场景说起
前面几篇,咱们搭的知识库问答系统已经能回答很多问题了。但很快你会发现:
用户问:“今天北京天气怎么样?”
系统答:“抱歉,知识库中没有关于天气的信息。”
用户:“…”
知识库只能回答"已知的、静态的"信息,但用户的问题可能是实时的、动态的——天气、股价、新闻…
这时候就需要Agent出场了。
二、Agent 是什么?和普通对话有什么区别?
2.1 一句话定义
Agent = LLM + 工具(Tools)+ 自主决策能力
普通对话:LLM 只用自己的"脑子"(训练数据)回答问题。
Agent 对话:LLM 可以"动手"——调用外部工具获取实时信息,然后再回答。
2.2 对比图
普通 LLM 对话: 用户提问 ──→ LLM ──→ 回答 ↑ └─ 只用训练数据 Agent 对话: 用户提问 ──→ LLM ──→ 需要实时数据?──→ 调用工具 ──→ 获取结果 ↑ ↓ └─ 结合训练数据 + 工具结果 ←────┘2.3 Chatchat 的 Agent 能力
Chatchat 0.3.x 对 Agent 做了大幅增强,支持:
| 能力 | 说明 |
|---|---|
| 工具调用 | 让模型自动选择并调用工具 |
| 多轮决策 | 复杂任务可以分多步执行 |
| 内置工具 | 搜索引擎、数据库、ARXIV、Wolfram 等 |
| 自定义工具 | 开发自己的工具接入系统 |
| Function Call | 结构化工具调用,更可靠 |
三、Agent 的核心机制:ReAct
3.1 什么是 ReAct?
ReAct =Reasoning(推理)+Acting(行动)
核心思想:LLM 不直接回答,而是先思考、再行动、再观察、再思考…循环直到解决问题。
3.2 ReAct 的循环过程
用户提问:"今天北京气温多少?适合穿什么衣服?" ↓ [思考 1] 用户问的是北京今天的天气和穿衣建议。 我需要先获取北京的实时天气数据。 ↓ [行动 1] 调用工具:search_weather(city="北京") ↓ [观察 1] 工具返回:北京今天晴,气温 15-25°C,微风 ↓ [思考 2] 现在有了天气数据。气温 15-25°C,比较舒适。 可以建议穿薄外套或长袖。 ↓ [行动 2] 不需要再调用工具了,直接生成回答 ↓ [最终回答] 北京今天天气晴,气温 15-25°C,建议穿薄外套...3.3 ReAct 的 Prompt 模板
你可以使用以下工具: {tools_description} 请按以下格式回答: 问题:用户的问题 思考:分析当前情况,决定下一步行动 行动:选择要调用的工具,格式为 {"tool": "工具名", "input": "参数"} 观察:工具返回的结果 ...(思考、行动、观察可以循环多次) 最终回答:基于所有观察结果,给出最终答案 开始! 问题:{user_question}四、Function Call:更靠谱的工具调用
4.1 传统 ReAct 的问题
传统 ReAct 是让模型自由生成工具调用指令,格式不固定,容易出错:
模型输出:"我需要查一下天气,让我调用 search_weather 工具,参数是北京" ↑ 这种自然语言描述,解析起来很费劲4.2 Function Call 的改进
Function Call 让模型输出结构化的 JSON,更可靠:
{"tool":"search_weather","input":{"city":"北京"}}支持 Function Call 的模型:
- GPT-4 / GPT-3.5-turbo
- Qwen2(通义千问)
- ChatGLM4
- Claude 3
4.3 Chatchat 中的 Function Call
Chatchat 的chat/completions接口兼容 OpenAI 的 Function Call 格式:
importopenai client=openai.OpenAI(api_key="EMPTY",base_url="http://localhost:7861/v1")# 定义可用工具tools=[{"type":"function","function":{"name":"search_weather","description":"查询指定城市的天气","parameters":{"type":"object","properties":{"city":{"type":"string","description":"城市名称"}},"required":["city"]}}}]# 发送请求response=client.chat.completions.create(model="qwen2-instruct",messages=[{"role":"user","content":"北京今天天气怎么样?"}],tools=tools,tool_choice="auto"# 让模型自动决定是否调用工具)# 模型可能返回工具调用请求ifresponse.choices[0].message.tool_calls:tool_call=response.choices[0].message.tool_calls[0]print(f"模型要调用工具:{tool_call.function.name}")print(f"参数:{tool_call.function.arguments}")五、Chatchat 内置工具详解
5.1 工具一览
Chatchat 内置了多种实用工具:
| 工具 | 功能 | 配置要求 |
|---|---|---|
| search_internet | 搜索引擎(Bing/Google) | 需要 API Key |
| search_arxiv | ARXIV 学术论文搜索 | 免费 |
| search_wolfram | Wolfram Alpha 计算 | 需要 App ID |
| database_chat | 数据库自然语言查询 | 配置数据库连接 |
| text2image | 文生图 | 需要文生图模型 |
| calculator | 计算器 | 无需配置 |
5.2 配置搜索引擎工具
# tool_settings.yamlsearch_internet:search_engine:bing# 或 googlebing_search_url:"https://api.bing.microsoft.com/v7.0/search"bing_subscription_key:"your-bing-api-key"top_k:35.3 在 WebUI 中使用 Agent
- 打开对话页面
- 勾选“启用 Agent”
- 选择要使用的工具(可多选)
- 输入问题,模型会自动判断是否需要调用工具
三种使用模式:
| 模式 | 操作 | 效果 |
|---|---|---|
| 全自动 | 启用 Agent + 选多个工具 | 模型自己决定调哪个 |
| 半自动 | 启用 Agent + 选单个工具 | 模型只填参数,不调选择 |
| 手动 | 不启用 Agent + 选单个工具 | 直接调用,不走 LLM |
六、自定义工具开发实战
6.1 工具的结构
一个工具需要包含:
# 伪代码:工具的标准结构classMyTool:name="my_tool"# 工具名称description="这个工具能做什么..."# 工具描述(给 LLM 看的)# 参数定义(JSON Schema 格式)args_schema={"type":"object","properties":{"param1":{"type":"string","description":"参数说明"}},"required":["param1"]}definvoke(self,params):"""执行工具逻辑"""result=do_something(params)returnresult6.2 实战:开发一个"查询公司库存"工具
# custom_tools/inventory_tool.pyfromtypingimportDict,AnyclassInventoryQueryTool:"""查询公司产品库存"""name="query_inventory"description="查询指定产品的库存数量。当用户询问某个产品是否有货、库存多少时,使用此工具。"args_schema={"type":"object","properties":{"product_name":{"type":"string","description":"产品名称,如'iPhone 15'、'MacBook Pro'"},"warehouse":{"type":"string","description":"仓库名称,可选。如'北京仓'、'上海仓'。不指定则查询所有仓库。"}},"required":["product_name"]}def__init__(self):# 实际项目中这里连接数据库或调用库存系统 APIself.mock_db={"iPhone 15":{"北京仓":100,"上海仓":50},"MacBook Pro":{"北京仓":20,"上海仓":30},}definvoke(self,params:Dict[str,Any])->str:product=params["product_name"]warehouse=params.get("warehouse")ifproductnotinself.mock_db:returnf"抱歉,未找到产品 '{product}' 的库存信息。"inventory=self.mock_db[product]ifwarehouse:count=inventory.get(warehouse,0)returnf"{product}在{warehouse}的库存为:{count}件"else:total=sum(inventory.values())details=", ".join([f"{k}:{v}件"fork,vininventory.items()])returnf"{product}总库存:{total}件({details})"# 注册工具fromchatchat.server.utilsimportregister_tool register_tool(InventoryQueryTool())6.3 工具注册到 Chatchat
# 在 server/tool/custom_tools.py 中注册from.inventory_toolimportInventoryQueryTool# 启动时自动加载defload_custom_tools():register_tool(InventoryQueryTool())6.4 测试自定义工具
importopenai client=openai.OpenAI(api_key="EMPTY",base_url="http://localhost:7861/v1")response=client.chat.completions.create(model="qwen2-instruct",messages=[{"role":"user","content":"iPhone 15 还有货吗?"}],tools=[{"type":"function","function":{"name":"query_inventory","description":"查询指定产品的库存数量","parameters":{"type":"object","properties":{"product_name":{"type":"string"}},"required":["product_name"]}}}],tool_choice="auto")print(response.choices[0].message.content)七、Agent 的局限与注意事项
7.1 当前局限
| 局限 | 说明 |
|---|---|
| 模型依赖 | 需要支持 Function Call 的模型,老模型不行 |
| 延迟较高 | 多轮工具调用会增加响应时间 |
| 错误传播 | 工具返回错误信息,模型可能"将错就错" |
| 成本问题 | 多轮调用消耗更多 Token |
7.2 最佳实践
- 工具描述要清晰:LLM 靠描述决定调不调用,描述不清会误调或漏调
- 参数要简单:复杂的嵌套参数模型容易填错
- 做好错误处理:工具内部要捕获异常,返回友好的错误信息
- 设置超时:防止工具卡死导致整个请求挂掉
- 记录调用日志:便于排查问题和优化
八、小结
这篇咱们把 Agent 的方方面面过了一遍:
✅ Agent 的定义:LLM + 工具 + 自主决策
✅ ReAct 机制:思考 → 行动 → 观察的循环
✅ Function Call:结构化的可靠工具调用
✅ Chatchat 内置工具:搜索、ARXIV、Wolfram、数据库等
✅ 自定义工具开发:从结构到实现的完整示例
✅ Agent 的局限和最佳实践
Agent 让 RAG 系统从"静态知识库"进化成了"动态智能助手",能处理更复杂的用户请求。
但记住:Agent 不是万能的。简单问答不需要 Agent,直接走知识库更快。Agent 适合需要实时数据、多步推理的复杂场景。
你在使用 Agent 时遇到过什么有趣或抓狂的情况?模型有没有"自作聪明"调错工具的时候?欢迎分享!
