起因
因公司近期需求,我需要进行一些agent的相关的学习,当然从我的感知中,我本以为我最开始的目的 **是做一个agent的产品** ,但是经过数次会议,我了解到我最终使命,是做出一个agent平台,他需要适应公司未来的发展
也要兼顾目前的使用,使我不得不进行一些学习。
如果是个人相关的产品的话 我会考虑 LangGraph,Mastra,Dify,CrewAI这类开源的产品去完成这项工作,但是实际上和我所预期的不太一致。我需要去从零去做一套适合我们自己的agent平台。所以开展了这一段新的学习过程。
个人想法
不管是否是因为什么原因去做这件事,这个事情是对自己有好处的。不光是增加自己的技能强度还有知识广度,并且让自己有更好的理解Agent。
最近状态
一转眼半年没更新了,好像又要打开这一系列的长时间的学习模式了。 虽然不知道为什么又要开始卷了,但是很多事情总得去做的。逃避解决不了任何问题。
学习前须知:
在LLM API设计之初,就又Message(消息)的概念,一般发给模型的消息为
[
{
"role": "system",
"content": "你是一个数学老师"
},
{
"role": "user",
"content": "1+1等于多少"
}
]
总共只会有三种角色
system
user
assistant
大概的概念是 System 是规则(背景故事) , User 是用户的请求 , assistant 就是AI的回复
举例
const messages = [
{
role:"system",
content:"你是一个专业的客服,只回答产品相关问题"
},
{
role:"user",
content:"你好"
},
{
role:"assistant",
content:"你好,请问有什么可以帮助你的?"
},
{
role:"user",
content:"你会写代码吗?"
}
]
对应
```bash
system:
你是一个专业客服,只回答产品相关问题
历史聊天:
用户你好
AI你好
用户你会写代码吗
```
后续模型公司提出了 Function Calling 的概念 , 它让 LLM 可以「请求调用某个工具」,但是工具本身的能力来自你的程序。 举个例子。
你定义一个工具
const calculator = {
name:"calculator",
description:"计算数学表达式",
execute(args){
return eval(args.expression)
}
}
这个工具本身有能力,但是 OpenAI(Qwen) 本身不知道 calculator 是什么,你通过 Function Calling 告诉 Qwen:
{
"tools":[
{
"type":"function",
"function":{
"name":"calculator",
"description":"计算数学表达式",
"parameters":{
"expression":"string"
}
}
}
]
}
有了上面的基础后,我们讨论Agent Runtime 的构成,LLM 是大脑。Runtime 是身体和神经系统。 ,以代码举例:
for(step=0; step<10; step++){
response = llm.chat(context)
if(response.final){
return
}
if(response.tool_call){
result = executeTool()
context.push(result)
}
}
抽象一下:
while(task_not_done){
Think
Act
Observe
}
也就是说:
Think: 我需要计算,所以调用 calculator
Act: 执行动作
Observe: 观察结果 -> 告诉Think
Think → tool_call → Act → Observe → Think → final
初始化建立文件
项目结构
agent-runtime-demo
├── runtime
│ └── runner.ts # Agent执行循环
│
├── agent
│ └── agent.ts # Agent定义
│
├── tools
│ └── calculator.ts # 工具
│
├── llm
│ ├── base.ts # LLM抽象
│ └── qwen.ts # Qwen实现
│
└── test
└── agent.test.ts # 测试
安装 openai
目前我们接入的是千问qwen,他们官方推荐的方式是以OpenAI Compatible API(OpenAI 兼容)方式接入。所以我们需要安装openAI的支持
pnpm add openai
定义 agent 配置
先不要处理过多东西,agent目前只作为配置。
// agent.tsx
import {tools} from "../tools/calculator";
export const agent = {
name: "calculator-agent",
instructions: `
你是一个助手。 如果需要计算,请调用calculator工具
`,
tools: [tools.calculator],
};
calculator 工具模块的定义
// calculator.ts
export const tools = {
calculator:{
name:"calculator",
description:"计算数学表达式",
parameters:{
type:"object",
properties:{
expression:{
type:"string",
description:"数学表达式,例如 123*456"
}
},
required:[
"expression"
]
},
async execute(args:any){
console.log(
"执行计算:",
args.expression
);
return eval(
args.expression
);
}
}
};
llm层的定义
// base.ts
export interface Message {
role: "system" | "user" | "assistant" | "tool";
content: string;
tool_call_id?: string;
}
export interface ToolDefinition {
type: "function";
function: {
name: string;
description: string;
parameters: any;
};
}
export type LLMResponse =
| {
type: "final";
content: string;
}
| {
type: "tool_call";
toolCall: {
id: string;
name: string;
arguments: any;
};
};
export interface LLM {
chat(params: {
messages: Message[];
tools?: ToolDefinition[];
}): Promise<LLMResponse>;
}
// qwen.ts
import OpenAI from "openai";
import { LLM, LLMResponse, Message, ToolDefinition } from "./base";
const client = new OpenAI({
apiKey:
"sk....",
baseURL: "https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1",
});
export class QwenLLM implements LLM {
async chat(params: {
messages: Message[];
tools?: ToolDefinition[];
}): Promise<LLMResponse> {
// console.log(JSON.stringify(params.tools, null, 2));
const res = await client.chat.completions.create({
model: "qwen3.7-plus",
messages: params.messages as any,
tools: params.tools as any,
temperature: 0.2,
});
const message = res.choices[0].message;
// 有工具调用
if (message.tool_calls) {
const call = message.tool_calls[0];
return {
type: "tool_call",
toolCall: {
id: call.id,
name: call.function.name,
arguments: JSON.parse(call.function.arguments),
},
};
}
// 普通回答
return {
type: "final",
content: message.content ?? "",
};
}
}
使用层的定义
import { QwenLLM } from "./llm/qwen";
import { run } from "./runtime/runner";
async function main() {
const llm = new QwenLLM();
const result = await run(
llm,
"帮我计算123*456",
);
console.log("最终答案:", result);
}
main();
最终结果
