-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
00ab3a9
commit 6ec43f0
Showing
2 changed files
with
198 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import Agent from '../lib/agent.js'; | ||
import Kimi from '../lib/kimi.js'; | ||
import { getAPIKey } from '../lib/apikey.js'; | ||
|
||
const apiKey = await getAPIKey(); | ||
|
||
const kimi = new Kimi({ | ||
apiKey | ||
}); | ||
|
||
const agent = new Agent(kimi, 'moonshot-v1-8k'); | ||
|
||
agent.registerTool('call', { | ||
description: '根据人名判断性别,如果是男孩子,会返回男,如果是女孩子,会返回女', | ||
parameters: { | ||
name: { | ||
type: 'string', | ||
description: '姓名,人的名字' | ||
} | ||
}, | ||
method: async function (args) { | ||
return Math.random() > 0.5 ? '男' : '女'; | ||
} | ||
}); | ||
agent.registerTool('searchAPI', { | ||
description: '搜索 API,根据需求、功能描述,找到可以实现该功能的接口', | ||
parameters: { | ||
query: { | ||
type: 'string', | ||
description: '问题描述,比如发送短信该用哪个 API' | ||
} | ||
}, | ||
method: async function (args) { | ||
return 'CreateInstance'; | ||
} | ||
}); | ||
|
||
agent.registerTool('searchProduct', { | ||
description: '根据意图确定产品是什么', | ||
parameters: { | ||
query: { | ||
type: 'string', | ||
description: '用户的意图,可能是在找一个功能,也可能是在找一个接口' | ||
} | ||
}, | ||
method: async function (args) { | ||
return `ecs`; | ||
} | ||
}); | ||
|
||
agent.registerTool('clicommand', { | ||
description: '参数,生成 aliyun 命令行语句,产品名依赖其它工具来进行判断', | ||
parameters: { | ||
product: { | ||
type: 'string', | ||
description: '产品名,产品名需要通过其它工具来进行确认' | ||
}, | ||
api: { | ||
type: 'string', | ||
description: 'API 名字' | ||
} | ||
}, | ||
method: async function (args) { | ||
return `aliyun ${args.product} ${args.api}`; | ||
} | ||
}); | ||
|
||
const [prompt] = process.argv.slice(2); | ||
await agent.chat(prompt); | ||
|
||
process.exit(0); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import { readAsSSE } from 'httpx'; | ||
|
||
function getTools(toolMap) { | ||
const tools = []; | ||
for (const [key, tool] of toolMap) { | ||
const properties = {}; | ||
for (const [paramName, parameter] of Object.entries(tool.parameters)) { | ||
properties[paramName] = parameter; | ||
} | ||
|
||
tools.push({ | ||
'type': 'function', | ||
function: { | ||
name: key, | ||
description: tool.description, | ||
parameters: { | ||
'properties': properties, | ||
'type': 'object' | ||
} | ||
} | ||
}); | ||
} | ||
|
||
return tools; | ||
} | ||
|
||
export default class Agent { | ||
constructor(kimi, model) { | ||
this.kimi = kimi; | ||
this.model = model; | ||
this.tools = new Map(); | ||
} | ||
|
||
registerTool(define, method) { | ||
this.tools.set(define, method); | ||
} | ||
|
||
async chatWithTool(message) { | ||
const response = await this.kimi.chat([ | ||
{ | ||
role: 'user', | ||
content: message | ||
} | ||
], { | ||
model: this.model, | ||
tools: getTools(this.tools) | ||
}); | ||
|
||
let toolCalls = []; | ||
let content = ''; | ||
for await (const event of readAsSSE(response)) { | ||
if (event.data !== '[DONE]') { | ||
const data = JSON.parse(event.data); | ||
|
||
const choice = data.choices[0]; | ||
if (choice.finish_reason !== 'tool_calls') { | ||
if (choice.delta.content) { | ||
content += choice.delta.content; | ||
} | ||
if (choice.delta.tool_calls) { | ||
const toolCall = choice.delta.tool_calls[0]; | ||
const index = toolCall.index; | ||
|
||
if (!toolCalls[index]) { | ||
toolCalls[index] = toolCall; | ||
} else { | ||
toolCalls[index].function.arguments += toolCall.function.arguments; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
return {content, toolCalls}; | ||
} | ||
|
||
async chat(promt) { | ||
const {content, toolCalls} = await this.chatWithTool(promt); | ||
const toolResults = []; | ||
for (const toolCall of toolCalls) { | ||
const result = await this.runTool(toolCall); | ||
toolResults.push({ | ||
role: 'tool', | ||
tool_call_id: toolCall.id, | ||
content: result | ||
}); | ||
} | ||
|
||
const messages = [ | ||
{role: 'user', content: promt}, | ||
{role: 'assistant', content, tool_calls: toolCalls}, | ||
...toolResults | ||
]; | ||
console.log(messages); | ||
const response = await this.kimi.chat(messages, { | ||
model: this.model, | ||
}); | ||
let lastEvent; | ||
let message = ''; | ||
for await (const event of readAsSSE(response)) { | ||
if (event.data !== '[DONE]') { | ||
const data = JSON.parse(event.data); | ||
const choice = data.choices[0]; | ||
if (choice.finish_reason === 'content_filter') { | ||
console.log(event); | ||
} else if (choice.finish_reason === 'stop') { | ||
lastEvent = event; | ||
Check failure on line 107 in lib/agent.js GitHub Actions / build (14.x)
Check failure on line 107 in lib/agent.js GitHub Actions / build (16.x)
Check failure on line 107 in lib/agent.js GitHub Actions / build (18.x)
|
||
} else if (!choice.finish_reason) { | ||
const content = choice.delta.content; | ||
if (content) { | ||
process.stdout.write(content); | ||
message += content; | ||
Check failure on line 112 in lib/agent.js GitHub Actions / build (14.x)
Check failure on line 112 in lib/agent.js GitHub Actions / build (16.x)
Check failure on line 112 in lib/agent.js GitHub Actions / build (18.x)
|
||
} | ||
} | ||
} else { | ||
console.log(); | ||
} | ||
} | ||
} | ||
|
||
async runTool(call) { | ||
const tool = this.tools.get(call.function.name); | ||
const args = JSON.parse(call.function.arguments); | ||
const result = await tool.method(args); | ||
return result; | ||
} | ||
} |