深度智能体需要特定模型吗?基于LangSmith的银行领域演示
从理论上讲,LangChain Deep Agents 是与模型无关的,但实际上却对模型敏感。通过 LangSmith 追踪的五功能银行智能体展示了不同模型在实际应用中的表现。
来源: Beyond Simple Agents: Engineering DeepAgents for Enterprise with LangChain — 2
使用 Deep Agents 框架设计智能体时,一个自然的后续问题是它是否需要特定的模型才能良好运行。诚实的答案可以分为两部分:从架构上来看,Deep Agents 并不关心你使用哪种模型;但在实际应用中,效果在很大程度上取决于你所选择的模型。
架构上与模型无关
该框架中没有强制规定必须使用特定模型,代码也体现了这一点。任何聊天模型都可以被接入:
from langchain.chat_models import init_chat_model
# Swap any model in — the harness doesn't care
agent = create_deep_agent(
model=init_chat_model("openai:gpt-4o"),
tools=[...],
system_prompt="..."
)
# Or Anthropic
agent = create_deep_agent(
model=init_chat_model("anthropic:claude-opus-4-6"),
tools=[...],
)
# Or Google
agent = create_deep_agent(
model=init_chat_model("google_vertexai:gemini-2.0-flash"),
tools=[...],
)
规划工具、文件系统、子智能体生成以及详细提示语,这四大核心要素均在框架层实现。LangGraph负责提供运行环境,而大语言模型则仅仅是接入该系统的推理引擎。
对模型依赖度较高
该框架依赖于某些模型表现并不一致的能力。
- 可靠的工具调用能力。整个流程依赖于模型能以正确格式并使用恰当参数来调用工具。性能较弱的模型会编造工具名称、传递错误的参数类型,或直接跳过调用步骤而用文字回答。
- 执行长篇系统提示语的能力。内置的提示语相当冗长,要求模型先进行规划、使用待办列表、将上下文分配给子智能体,并自行检查工作成果。那些无法良好遵循指令的模型会在任务进行到一半时偏离正确路径。
模型的大致表现水平
| 模型层级 | 在复杂任务中的表现 |
|---|---|
| 前沿模型 | 能够可靠地使用工具,遵循复杂指令,在长时间任务中保持连贯性 |
| 性能较强的中等层级模型 | 适用于大多数任务,但在极长的任务链中偶尔会出现问题 |
| 规模较小或开源模型 | 表现不稳定:工具格式错误、指令理解偏差以及过早终止现象较为常见 |
这些层级名称仅为撰写时的示例,模型排名变化迅速,因此请以您自己的任务作为测试标准。
核心要点
可以把这想象成一辆可更换发动机的赛车:无论安装何种发动机,最高速度都由该发动机决定。框架则提供结构支撑,包括规划、内存、子代理以及路由功能。而模型则负责确保所有这些组件能够被正确使用。在实际应用中,尤其是在银行领域,若使用伪造的自动取款机列表或虚假的投资顾问,可能会造成严重后果,因此应选用前沿模型,切勿在模型质量上妥协。
开始构建吧
理论已经讲够了。那种仅有文档而没有实际代码的例子有个著名的笑话:两百页的文档、十五张图表、一份精心撰写的README,却没有任何可以运行的代码。因此这里提供一个包含五种银行工具及模拟数据的可运行演示。
快速入门
在 Anthropic 控制台创建一个 API 密钥,然后设置一个项目:
mkdir firstdeepagent && cd firstdeepagent
uv add deepagent anthropic
export ANTHROPIC_API_KEY='asdkjfbaepiufas;dkjcnaisdf'
touch agent.py bank_tools.py mock_data.py
这些命令会创建文件夹、安装软件包、导出密钥(请使用您自己的真实密钥,切勿使用已提交到版本控制中的密钥),并生成三个文件。bank_tools.py所依赖的工具包括:
from mock_data import (OFFICERS_DATA, PORTFOLIO_DATA, ATM_DATA,
RETIREMENT_DATA, LOCATIONS_DATA)
def get_atm_centers(zipcode: str) -> dict:
data = ATM_DATA.get(str(zipcode).strip())
if not data:
return {
"error": f"No ATM data for zipcode '{zipcode}'.",
"available_zipcodes": list(ATM_DATA.keys()),
}
return {"zipcode": zipcode, "atm_centers": data, "total": len(data)}
def get_investment_officers(city: str) -> dict:
key = city.strip().lower()
data = OFFICERS_DATA.get(key)
if not data:
return {
"error": f"No investment officers found in '{city}'.",
"available_cities": [c.title() for c in OFFICERS_DATA],
}
return {"city": city, "officers": data, "total": len(data)}
def get_portfolio_companies(sector: str = "all") -> dict:
companies = PORTFOLIO_DATA
if sector and sector.lower() != "all":
companies = [c for c in companies if sector.lower() in c["sector"].lower()]
return {"companies": companies, "total": len(companies), "total_aum": "$6.35B"}
def get_retirement_plans(plan_type: str = "all") -> dict:
plans = RETIREMENT_DATA
if plan_type and plan_type.lower() != "all":
plans = [
p for p in plans
if plan_type.lower() in p["name"].lower() or plan_type.lower() in p["type"].lower()
]
return {"plans": plans, "total": len(plans)}
def get_bank_locations(city: str = "all") -> dict:
locations = LOCATIONS_DATA
if city and city.lower() != "all":
locations = [l for l in locations if city.lower() in l["city"].lower()]
total_branches = sum(l["branches"] for l in locations)
return {"locations": locations, "total_branches": total_branches}
mock_data模块用于存储示例记录,而tools-config模块则保存工具的架构、名称与函数之间的映射关系以及系统提示语。将它们放在不同的文件中,有助于保持代理代码的简洁。agent.py的主循环结构如下:
import os
import json
import anthropic
from tools_config import TOOL_SCHEMAS, TOOL_FN_MAP, SYSTEM_PROMPT
def run_agent(client: anthropic.Anthropic, conversation: list[dict]) -> str:
MAX_ITERATIONS = 10
messages = list(conversation)
for _ in range(MAX_ITERATIONS):
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=2048,
system=SYSTEM_PROMPT,
tools=TOOL_SCHEMAS,
messages=messages,
)
tool_use_blocks = [b for b in response.content if b.type == "tool_use"]
if not tool_use_blocks:
text_parts = [b.text for b in response.content if b.type == "text"]
return "\n".join(text_parts).strip()
tool_results = []
for block in tool_use_blocks:
fn = TOOL_FN_MAP.get(block.name)
result = fn(**block.input) if fn else {"error": f"Unknown tool: {block.name}"}
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps(result),
})
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})
return "[Max iterations reached — partial answer may be incomplete.]"
def main():
api_key = os.environ.get("ANTHROPIC_API_KEY")
if not api_key:
print("Error: ANTHROPIC_API_KEY environment variable not set.")
print(" export ANTHROPIC_API_KEY=your_key_here")
raise SystemExit(1)
client = anthropic.Anthropic(api_key=api_key)
conversation: list[dict] = []
print("XYZ Bank Agent — type 'quit' to exit.\n")
while True:
try:
user_input = input("You > ").strip()
except (EOFError, KeyboardInterrupt):
print("\nGoodbye!")
break
if not user_input:
continue
if user_input.lower() in {"quit", "exit", "q"}:
print("Goodbye!")
break
conversation.append({"role": "user", "content": user_input})
answer = run_agent(client, conversation)
conversation.append({"role": "assistant", "content": answer})
print(f"\n{answer}\n")
if __name__ == "__main__":
main()
运行它
确保密钥已导出,然后使用 uv run agent.py 启动代理。示例会话如下:
XYZ Bank Agent — type 'quit' to exit.
You > Who are the investment officers in Chicago? Also what retirement plans do you offer?
Here's everything you need!
---
## 👔 Investment Officers in Chicago
| Name | Title | Specialty | Phone | Email |
|---|---|---|---|---|
| **Margaret Chen** | Senior Investment Officer | Equities & ETFs | 312-555-0101 | m.chen@xyzbank.com |
| **David Okafor** | Investment Officer | Fixed Income | 312-555-0182 | d.okafor@xyzbank.com |
| **Sarah Kowalski** | Wealth Manager | Retirement Planning | 312-555-0147 | s.kowalski@xyzbank.com |
---
## 🏦 Retirement Plans Offered by XYZ Bank
1. **XYZ Gold 401(k)**
- Min. Contribution: $50/month | Employer match up to 6%
- Features: Roth option, target date funds, low expense ratios
2. **XYZ Silver IRA (Traditional)**
- Min. Contribution: $25/month
- Features: Tax-deferred growth, flexible contributions, 600+ fund choices
3. **XYZ Roth IRA**
- Min. Contribution: $25/month
- Features: Tax-free withdrawals, no required minimum distributions, estate planning benefits
4. **XYZ Executive SEP-IRA**
- Contribute up to 25% of income
- Features: High contribution limits, self-employed friendly, simple administration
---
If you'd like to learn more about any of these plans or get in touch with one of our Chicago investment officers (especially **Sarah Kowalski**, who specializes in retirement planning!), feel free to ask! 😊
You >
该代理会将请求拆解为可执行的步骤,选择合适的工具,运行这些工具并收集结果。如果思维导图有助于理解流程,其顺序为:接收问题、制定计划、调用工具、汇总结果、给出最终答案。
可观测性
这样的系统需要遥测功能,因此可以加入LangSmith。集成非常简单:只需两个环境变量和大约三行代码即可。LangSmith会封装你现有的调用方式,而非直接替换它们。
该脚本直接调用Anthropic SDK而非LangChain,因此若需更详细的追踪信息,可选择用@traceable装饰run_agent()函数:
from langsmith import traceable
@traceable(name="xyz-bank-agent-run")
def run_agent(client, conversation):
....................
....................
每次工具调用、模型决策、令牌数量以及延迟都会显示在 LangSmith 仪表板上,且不会对智能体循环进行任何重构。可以用更复杂的问题再次运行它:
uv run agent.py
XYZ Bank Agent — type 'quit' to exit.
You > Show ATMs in 10001, investment officers in New York, and all branch locations
Here's a complete overview across all three categories:
---
## 🏧 ATMs in ZIP Code 10001
| ATM Name | Address | Hours | Fee |
|---|---|---|---|
| Midtown Manhattan ATM | 350 5th Ave | 24/7 | No fee |
| Penn Station ATM | 8 W 31st St | 24/7 | $2.50 (non-members) |
---
## 💼 Investment Officers — New York
1. **James Thornton** — Chief Investment Officer
- Specialty: Alternative Assets
- 📞 212-555-0201 | ✉️ j.thornton@xyzbank.com
2. **Priya Nair** — Investment Officer
- Specialty: ESG Portfolios
- 📞 212-555-0233 | ✉️ p.nair@xyzbank.com
---
## 🏦 All Branch Locations (61 Branches Nationwide)
| City | Branches | Flagship Address | Hours |
|---|---|---|---|
| Chicago | 14 | 200 W Adams St, Chicago IL 60606 | Mon–Fri 9am–5pm, Sat 9am–1pm |
| New York | 22 | 1 World Trade Center, NY 10007 | Mon–Fri 8am–6pm, Sat 9am–2pm |
| Los Angeles | 11 | 333 S Grand Ave, LA 90071 | Mon–Fri 9am–5pm, Sat 9am–1pm |
| Houston | 8 | 1000 Main St, Houston TX 77002 | Mon–Fri 9am–5pm |
| Boston | 6 | 100 Federal St, Boston MA 02110 | Mon–Fri 9am–5pm, Sat 10am–1pm |
---
Is there anything else you'd like to explore, such as retirement plans or our investment portfolio? 😊
You > What companies are in XYZ Bank's portfolio? List only Technology sector companies
Here are the **Technology sector companies** in XYZ Bank's investment portfolio:
---
## 💻 Technology Portfolio Companies
| Company | Stake | Value | Rating |
|---|---|---|---|
| **Apex Technologies Inc.** | 4.2% | $840M | A+ |
| **Sentinel Cybersecurity** | 7.3% | $1.5B | A+ |
---
### 📊 Summary
- **Total Technology Holdings:** 2 companies
- **Total Portfolio AUM:** $6.35B
- Both companies carry an **A+ rating**, reflecting strong investment quality.
---
Would you like to explore other sectors, view the full portfolio, or learn about our investment officers? Let me know! 😊
You >
接着打开 LangSmith 网站,查看记录的运行结果。每次运行都会列出对应的步骤,包括输入数据、输出结果、耗时以及错误信息。
免费套餐
在撰写本文时,Developer 套餐是免费的,每月可使用 5,000 次追踪功能,且无需信用卡。该套餐提供对每一步的完整追踪与调试功能,涵盖输入数据、输出结果、延迟时间、令牌使用情况以及错误信息,同时还配有即时代码测试环境。该套餐仅限一个账号和一个工作空间使用,追踪数据保留时间为 14 天,非常适合个人原型设计和概念验证。LangSmith 表示不会利用用户的追踪数据来训练模型,这些数据将始终保留在用户所在组织内部。在依赖这些限制条件之前,请先查看当前的套餐详情。
简而言之,先从免费层级开始使用。它无需付费,配置大约需要十五分钟,且能立即显示所有的工具调用和决策过程。只有当实际业务流量接近阈值时再升级。
下一步该做什么
- 用核心银行系统、CRM或内部API等真实数据源替代模拟数据。
- 构建层级结构,由网关协调器将请求路由到各领域代理。
- 设置规则,礼貌地拒绝超出范围的问题并将请求转交给人工处理。
- 利用Redis或数据库保存多轮对话的历史记录。
- 添加跨会话记忆功能,以便记住回头用户的过往查询和偏好设置。
- 为每个用户及每次会议设定速率限制和令牌额度。
- 准备30到50个具有代表性的查询示例,并标注预期输出结果。