跳到正文
astorlm
语言: 简体中文
← 地图

第 1 关

什么是智能体?

几乎任何用到语言模型的东西都会被叫作“智能体”。有用的定义要窄得多,归结起来只有一个问题:下一步由谁决定?在智能体里,由模型决定。
1/16 手风琴褶数:
  • user
  • assistant
  • tool_result
一位村民弄丢了村里宝箱的钥匙。Astor,也就是智能体循环,把问题连同两个工具 ask_villager 和 search_area 一起带给神谕者。地图的大部分还是黑的。

EventBus

问题

一个聊天机器人、一个调用两次模型的脚本、一个能自己修 bug 的系统,都被叫作智能体。这让人很难弄清自己到底在构建什么,更难为手头的工作选对工具。

这段动画是一个小小的冒险游戏。一位村民问:“我把村里宝箱的钥匙弄丢了。它在哪儿?”游戏里有两个函数能帮上忙:ask_villager 向某人打听他看到了什么,search_area 在地图上的某个地点搜索。注意看:是谁决定运行哪一个,又是在什么时候。

是什么让它成为智能体

智能体不是“带工具的 LLM”,也不是“聪明的工作流”。它是一个由模型来选择控制流的系统:调用哪个工具、按什么顺序、什么时候停下。你的代码从来不会写“先问渔夫,再搜橡树”。模型读完每个结果,再决定下一步。

让这一切成为可能的循环,就是下一关的内容。

动画里的角色

村民 你的应用
问题从村里的一所房子出发,答案也回到那里。
Astor 循环
智能体循环,背着装满消息的班多钮手风琴。神谕者的纸条让他去哪儿他就去哪儿,别的地方一概不去。
神谕者 LLM
模型,待在两堆篝火之间的洞穴里。它从不出门:只知道手风琴里装着的东西。没有工具时,它只能动嘴,就像惰者 Petrus。
码头和树林 工具
ask_villager 和 search_area:你自己的函数。一屏地图会一直黑着,直到有路通向它。
被点亮的屏幕 控制流
整个模式浓缩在一张图里,小地图上也有。每条路只在神谕者读完上一个结果、申请调用对应工具时才会出现。如果是工作流,你的代码会在任何人提问之前就把所有的路画好。山一直是黑的:模型从来不需要它。
卢比和红心 tokens、maxTurns
每次拜访神谕者都要花卢比,因为整个手风琴都要重新读一遍,还要花掉轮数预算里的一颗红心。数字仅作示意。

代码

使用 astorlm:用 tool() 包装你自己的函数,再交给智能体。循环是内置的:调用哪些工具、按什么顺序、什么时候信息足够回答,都由模型来选。

从零手写:把你游戏里的函数作为工具交给模型。循环本身就是第 2 关的那个;唯一的新东西是它拿到了哪些工具。

import { OpenAIProvider, createLocalAgent, tool } from 'astorlm'
import { z } from 'zod'

// Any OpenAI-compatible endpoint: OpenAI, Ollama, LM Studio, vLLM, a proxy…
const provider = new OpenAIProvider({
  baseURL: 'http://localhost:11434/v1', // e.g. Ollama's default address
  model: 'your-model', // e.g. 'llama3.1', 'gpt-4o-mini'
  apiKey: 'YOUR_API_KEY', // local servers usually ignore it
})

// Your own game functions, wrapped as tools: a name, a description and an input schema.
const askVillager = tool({
  name: 'ask_villager',
  description: 'Ask someone in the village what they saw. Returns what they say.',
  schema: z.object({ name: z.string().describe('Who to ask, e.g. "fisher" or "baker"') }),
  execute: async ({ name }) => world.villager(name).say(),
})

const searchArea = tool({
  name: 'search_area',
  description: 'Search one spot on the map. Returns what is found there, if anything.',
  schema: z.object({ area: z.string().describe('A named spot, e.g. "old oak" or "bridge"') }),
  execute: async ({ area }) => world.search(area),
})

// The model decides which tools to call, in what order, and when to stop.
const agent = await createLocalAgent({
  provider,
  tools: [askVillager, searchArea],
  maxTurns: 5, // a cap on the laps, in case it never settles
})

await agent.run('I lost the key to the village chest. Where is it?') // "In the crow's nest on the old oak"

何时使用,以及代价是什么

  • 当你没法事先把步骤写下来时,就用它。钥匙可能在鸟窝里、在桥底下,或者已经被卖到了商店:写成代码的话,每种新情况都是又一个分支。只要有工具,智能体用同一个循环就能应付它们。
  • 每一步都是一次模型调用。这里两个工具意味着三次调用。步骤越多,延迟越高、token 越多,所以要用 maxTurns 限制圈数。
  • 同一个问题可能走出不同的路径。把模型选择的路径记录下来,这样你才能看清一个答案为什么会是这样。
  • 工具就是边界。模型只能做你的工具允许的事。你交给它什么,它就可能弄坏什么。