跳到正文

基于数据库的智能体 ​

机器翻译

本页由英文原文机器翻译而来,尚未经过母语审校,欢迎在 GitHub 上提出修改。内容如有出入,以英文原文为准。

任务: 让一个助手根据商店的数据库回答"哪些商品快缺货了?",而从不让模型编写 SQL。

yaml
# Recipe: an agent that answers from your database through tools you write.
paths:
  components: ./components
  migrations: ./migrations

datasources:
  db:
    driver: sqlite
    database: ./data/shop.db

llm:
  model: phi3
sql
CREATE TABLE products (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    stock INTEGER NOT NULL
);

INSERT INTO products (name, stock) VALUES
    ('Mug', 40), ('Monitor', 2), ('Cable', 3), ('Keyboard', 25);

工具是你编写的一个函数,里面只有一个只读查询。模型看到它的名字、描述和参数; 它决定是否调用、用什么值调用,这个值会在查询运行之前被转换成参数的类型。 stock_result.actions 列出每一次调用的完整写法。

xml
<q:component name="Assistant">
  <!-- The model never writes SQL: it picks a tool and its arguments. The
       tool is a read-only query you wrote; its q:param says the argument's
       type, and the model's value is converted to it before the query runs. -->
  <q:agent name="stock" maxIterations="4" timeout="60000" onerror="continue">
    <q:instruction>You help a shop owner. Use the tools to look at the data,
      then answer in one sentence.</q:instruction>

    <q:tool name="low_stock" description="Products with fewer units in stock than `below`">
      <q:param name="below" type="integer" default="5" />
      <q:function name="lowStock">
        <q:query name="rows" datasource="db">
          SELECT name, stock FROM products WHERE stock &lt; :below ORDER BY stock
          <q:param name="below" value="{below}" type="integer" />
        </q:query>
        <q:return value="{rows}" />
      </q:function>
    </q:tool>

    <q:execute task="Which products are running out of stock?" />
  </q:agent>

  <ui:window title="Stock assistant">
    <q:if condition="stock_result.success">
      <ui:text>{stock}</ui:text>
      <q:else>
        <ui:alert variant="warning">The assistant did not finish: {stock_result.error.message}</ui:alert>
      </q:else>
    </q:if>
    <!-- Every tool call the agent made, written out. -->
    <q:loop items="{stock_result.actions}" var="a">
      <ui:text>Called {a.call}</ui:text>
    </q:loop>
  </ui:window>
</q:component>
xml
<!-- Structural checks, never the model's exact words: the same tests run
     against a real model before every release. -->
<q:test name="the agent looks at the data through its tool" page="/">
  <test:visit />
  <test:expect text="Called low_stock(" />
  <test:expect no-text="did not finish" />
  <test:expect table="products" count="4" />
</q:test>

在 CI 中,替身模型按照一个简短的脚本行事——调用工具,然后结束:

json
[
  {"when": "Which products are running out of stock?",
   "replies": ["{\"action\": \"low_stock\", \"args\": {\"below\": 5}}",
               "{\"action\": \"finish\", \"result\": \"Monitor (2) and Cable (3) are running out.\"}"]}
]
text
tests/agent.test.q
  PASS  the agent looks at the data through its tool
1 passed, 0 failed

工具能做它的函数体所做的一切,而提示词可以引导模型去调用它:只给工具完成任务所需的访问权限。

已测试: 在 CI 中,这些测试针对一个替身模型服务器运行,它根据收到的第一个来源作答;每次发布前,它们针对真实模型运行(tests/live_ai/test_cookbook_ai.py)。因此它们检查的是结构——哪个来源、哪个工具、失败时页面显示什么——而从不检查模型的措辞。

参见 IA-4 和 IA-5。

MIT 许可证 · 使用 VitePress 构建