编写操作处理程序
在Adobe LLM Apps UI中创建操作后,元数据存储在LLM Apps API中,但尚未包含代码。 本指南将指导您编写在LLM平台(如ChatGPT或Claude)调用您的操作时运行的处理程序函数。
有关项目布局、本地开发和测试的详细信息,请参阅开发。
开发人员合同
您只编写处理程序。 所有其他功能(操作名称、描述、输入架构、注释、构件可见性、权限、CSP)都位于LLM Apps UI中,并在部署时自动交付到运行时。 您永远不会在存储库中手动编辑元数据,也永远不会在代码中注册工具。
actions/<name>/index.jsactions.json (元数据快照)快速入门
链接存储库需要项目结构才能编写处理程序。 克隆 Adobe LLM应用程序模板 以空起点开始。
将内容推送到您在应用程序创建期间链接的存储库(例如,your-org/your-repo)。
代码就绪后,运行:
npm install
这将安装所有依赖项,包括@adobe/llm-apps-runtime — 处理MCP协议通信、操作发现和请求路由的运行时。 您不直接与运行时交互;entry.js在生成时使用该运行库。
处理程序合同
处理程序是位于actions/<name>/index.js的单个文件,用于导出一个异步函数:
module.exports = async (args) => {
return {
content: [{ type: 'text', text: 'response for the LLM' }],
structuredContent: { /* data for the widget */ }
}
}
函数将操作的输入参数作为纯对象进行接收 — 这些参数是在“创建操作”对话框中定义的参数。 服务器在调用处理程序之前根据输入架构验证它们。
content (必需)
发送到LLM和纯文本主机的内容部分的数组。 LLM平台将读取这一点来制定其响应。
content: [
{ type: 'text', text: 'Found 5 products matching category "bagged-coffee".' }
]
始终返回content — 它是任何主机的通用回退。
structuredContent
发送到小部件的纯JavaScript对象。 此数据具有零令牌成本 — 它由EDS小组件块使用,以呈现丰富的UI,如产品轮播或映射。
structuredContent: {
products: [
{ name: 'Product A', category: 'bagged-coffee', imageUrl: '...' },
{ name: 'Product B', category: 'bagged-coffee', imageUrl: '...' }
],
total: 2,
category: 'bagged-coffee'
}
结构由您决定 — 它必须通过bridge.toolResult匹配您的EDS小组件块的预期内容。
structuredContent必须是纯对象,而不是空数组。_meta(可选)
与结果一起发送的其他元数据。 openai/widgetDescription键可告知LLM平台如何呈现构件:
_meta: {
'openai/widgetDescription': 'The widget displays a scrollable product carousel. '
+ 'Do NOT repeat the product list. Instead, highlight one or two recommendations.'
}
示例:搜索产品处理程序
以下是search-products处理程序示例。 它接受可选的category过滤器和自由文本query,搜索产品目录,并返回LLM的文本摘要和构件轮播的结构化数据。
// actions/search-products/index.js
const PRODUCTS = [
{
name: 'Product A',
description: 'A short description of Product A.',
category: 'bagged-coffee',
sub_category: 'dark-roast',
image_url: 'https://www.example.com/products/product-a/hero.jpg',
url: 'https://www.example.com/products/product-a',
productId: 'PROD-001',
rating: 4.7,
reviewCount: 58
},
// ... more products
];
const WIDGET_DESCRIPTION = 'The widget displays a scrollable product carousel '
+ 'with images, star ratings, and review counts. Do NOT repeat the product list.';
module.exports = async ({ category = '', query = '' } = {}) => {
let results = PRODUCTS;
if (category) {
const categoryLower = category.toLowerCase();
results = results.filter((p) =>
p.category.toLowerCase().includes(categoryLower)
|| p.sub_category.toLowerCase().includes(categoryLower)
);
}
if (query) {
const queryLower = query.toLowerCase();
results = results.filter((p) =>
p.name.toLowerCase().includes(queryLower)
|| p.description.toLowerCase().includes(queryLower)
);
}
const products = results.map((p) => ({
productId: p.productId,
name: p.name,
shortDescription: p.description,
category: p.category,
rating: p.rating,
reviewCount: p.reviewCount,
imageUrl: p.image_url,
productUrl: p.url,
}));
if (products.length === 0) {
return {
content: [{ type: 'text', text: `No products found for "${category}".` }],
structuredContent: { products: [], total: 0, category: null },
_meta: { 'openai/widgetDescription': WIDGET_DESCRIPTION }
};
}
return {
content: [
{ type: 'text', text: `Found ${products.length} product(s) in "${category}".` }
],
structuredContent: { products, total: products.length, category },
_meta: { 'openai/widgetDescription': WIDGET_DESCRIPTION }
};
};
运行时发生的情况:
- 用户请求LLM平台“给我看你的咖啡产品”。
- LLM平台与 搜索产品 的意图匹配并提取
category。 - MCP服务器使用
{ category: 'bagged-coffee' }调用您的处理程序。 - 您的处理程序将筛选目录并返回
content(LLM的文本摘要)+structuredContent(小组件的产品数组)。 - LLM平台显示文本响应,并将结构化数据传递到EDS小组件,该小组件将呈现产品轮播。
如果缺少处理程序,该怎么办?
如果您在UI中定义了操作,但尚未创建处理程序文件,则该操作仍会在部署时注册。 调用将使用默认存根处理程序,该处理程序会返回空内容,直到您添加实际代码为止。 这意味着您可以先在UI中定义所有操作,然后递增地实施它们。