接入前端工具
让智能体调用网页函数,并用返回值继续回答。
让智能体按需读取当前页面,或执行页面上的动作。你在智能体里声明工具,在 Kit 页面实现同名回调;Kit 把结果送回会话,智能体继续回答。
准备接入
准备一个能回复的 Kit 页面、服务智能体的公开 ID(agent_…),以及宿主后端的 API Key。下面以读取课程选择为例,不需要视频、数据库或额外依赖。宿主网站须已有验证登录态的 POST /api/praxis-token 路由,返回 { token },详见嵌入令牌与用户。它是你的路由,不是 Praxis API。
前端工具适合按需读取。每条消息都需要的小事实,使用页面上下文。
在智能体声明工具
将以下文件保存为 register-tool.ts,替换 agent_example,在已注入 PRAXIS_API_KEY 的服务端运行 bun register-tool.ts。它先读取智能体,再通过公开 API 更新 tools,保留其他工具,并用当前 version 防止覆盖并发修改。
// register-tool.ts — run on the server with: bun register-tool.ts
const key = process.env.PRAXIS_API_KEY;
if (!key) throw new Error("Set PRAXIS_API_KEY on the server");
const url = "https://api-develop.deepraxis.com/agent/v1/agents/agent_example";
const headers = { Authorization: `Bearer ${key}`, "Content-Type": "application/json" };
const currentResponse = await fetch(url, { headers });
if (!currentResponse.ok) throw new Error(`Read failed: ${currentResponse.status}`);
const current = await currentResponse.json();
const tool = {
type: "custom",
name: "read_selected_lesson",
description: "Read the selected lesson when the user asks which lesson is open.",
input_schema: { type: "object", properties: {}, additionalProperties: false },
};
const tools = [...(current.tools ?? []).filter(
(item: { type: string; name?: string }) =>
!(item.type === "custom" && item.name === tool.name),
), tool];
const response = await fetch(url, {
method: "POST", headers,
body: JSON.stringify({ version: current.version, tools }),
});
if (!response.ok) throw new Error(`Update failed: ${response.status}`);
const saved = await response.json();
console.log({ id: saved.id, version: saved.version });预期结果: 终端输出智能体 ID 和新版本。让宿主签发新版本的令牌,再开始新会话;已固定旧版本的令牌或已有会话不会自动换到新定义。若嵌入策略固定版本,在控制台更新接入版本,或签发时明确指定新 version。
工具名须匹配 ^[a-zA-Z0-9_-]{1,64}$,不能与其他自定义工具或内置工具重名。input_schema.type 必须是 object;描述要说明何时调用。仅在页面实现函数,不会把工具自动加入智能体。
实现页面回调
将下面的 HTML 放到宿主网站。它使用 Develop 的 Kit 和 API;页面来源需要在嵌入策略中获准。
<!doctype html>
<html lang="zh-CN">
<meta charset="utf-8" />
<title>课程助手</title>
<label>当前课程
<select id="lesson">
<option value="第三课:配送规则">第三课:配送规则</option>
<option value="第四课:退货流程">第四课:退货流程</option>
</select>
</label>
<output id="tool-status" aria-live="polite"></output>
<praxis-agent style="display:block;height:600px"></praxis-agent>
<script type="module">
import "https://kit-develop.praxisusercontent.com/v1/praxis-kit.js";
await customElements.whenDefined("praxis-agent");
const chat = document.querySelector("praxis-agent");
const lesson = document.querySelector("#lesson");
chat.onClientTool = async ({ name }) => {
if (name !== "read_selected_lesson") throw new Error(`Unknown tool: ${name}`);
return { title: lesson.value };
};
chat.addEventListener("praxis.tool.change", event => {
const { name, status, isError } = event.detail;
document.querySelector("#tool-status").textContent =
`${name}: ${status}${isError ? " (error)" : ""}`;
});
chat.addEventListener("praxis.log", event => console.warn(event.detail));
chat.setOptions({
api: {
url: "https://api-develop.deepraxis.com",
getToken: async () => {
const response = await fetch("/api/praxis-token", {
method: "POST", credentials: "same-origin",
});
if (!response.ok) throw new Error(`Token request failed: ${response.status}`);
const { token } = await response.json();
if (typeof token !== "string" || !token) throw new Error("Missing token");
return token;
},
},
agent: { name: "课程助手" },
});
</script>
</html>onClientTool 是元素的 JavaScript 属性,不能放进 HTML 属性或 setOptions。回调收到 { id, name, input },分别是调用编号、工具名和输入;参数应由你的函数校验。对未知工具名抛错,不要返回成功。
字符串返回值原样发送,其他可序列化值转成 JSON 文本,undefined 转成空字符串。抛错、Promise 拒绝或序列化失败会作为错误结果返回。不要在结果里放其他用户的数据或凭据。
验证调用与恢复
询问「请调用工具告诉我正在看哪一课」。预期结果: 页面状态依次显示 start、end,智能体根据工具返回的课程回答。换课后再次提问,返回当前选择。end 表示服务端已接收结果,不代表整轮回复结束。
| 现象 | 检查与处理 |
|---|---|
| 没有调用 | 确认新会话使用含工具定义的版本,描述明确说明触发情境 |
返回 not available on this page | 在调用前给元素赋上 onClientTool |
| 回调失败 | 修正输入校验或页面逻辑;错误结果会交给智能体 |
praxis.log 报结果提交失败 | 回调不会自动重跑;核对网络及会话状态,勿盲目重做有副作用的动作 |
服务端最多等待 120 秒;超时记入错误结果后继续。Kit 会认领调用编号,并检查历史结果以避免重复执行,但这不是跨标签页事务保证。会改变业务数据的工具必须由后端鉴权并做幂等处理。
授权与下一步
前端 custom 工具不经过平台的工具确认卡。需要用户确认的页面动作,由你的界面处理;真正的数据权限必须在后端检查,不能依赖浏览器或模型参数。