You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在函数中从子进程返回值?JS调用Python子进程场景

解决Bot Framework中JS调用Python子进程返回值及Context报错问题

你的问题核心在于两个关键点:一是异步子进程的返回值无法正确传递,二是Context在回调中被回收导致报错。让我一步步帮你解决:

问题根源

  1. 返回值无效:你在stdout.on('end')回调里的return output只是回调函数的返回值,根本不会成为外层searchForRelevantDoc函数的返回值——因为子进程是异步执行的,外层函数会先于回调结束,直接return自然拿不到结果。
  2. Context被回收:Bot Framework的context对象有生命周期,当onTurn方法执行完毕后,框架会销毁这个context(也就是报错里的“proxy revoked”)。你之前在子进程回调里调用context.sendActivity时,turn已经结束,context已经失效了。

解决方案:用Promise包裹异步操作

我们需要把整个子进程的逻辑包装成Promise,这样外层的async函数就能通过await等待子进程完成,拿到正确的返回值,同时确保在onTurn的生命周期内使用context。

第一步:修改searchForRelevantDoc函数

把异步的子进程操作封装成Promise,在子进程结束时resolve结果,出错时reject错误:

const path = require('path'); // 引入path模块处理路径,避免相对路径问题

async function searchForRelevantDoc(context) {
  const msg = context.activity.text;
  // 用Promise包裹子进程逻辑
  return new Promise((resolve, reject) => {
    // 使用path.resolve确保脚本路径正确(基于当前JS文件的目录)
    const scriptPath = path.resolve(__dirname, '../path/to/file.py');
    const py = require('child_process').spawn('python', [scriptPath, msg]);
    let output = '';

    // 收集标准输出
    py.stdout.on('data', (data) => {
      output += data.toString();
      console.log('output was generated: ' + output);
    });

    // 处理错误输出
    py.stderr.on('data', (data) => {
      console.error('Python script error:', data.toString());
      // 可选:如果脚本报错需要终止,可以在这里reject
      // reject(new Error(`Python error: ${data.toString()}`));
    });

    // 子进程结束时resolve结果
    py.on('close', (code) => {
      console.log('Final output: ' + output);
      console.log(`Python script exit code: ${code}`);
      resolve(output);
    });

    // 处理子进程启动失败的情况(比如Python没安装、路径错误)
    py.on('error', (err) => {
      console.error('Failed to start Python subprocess:', err);
      reject(err);
    });
  });
}

第二步:修改调用逻辑

因为searchForRelevantDoc现在返回的是Promise,所以调用时必须用await等待结果,确保拿到的是实际的输出字符串,而不是Promise对象:

// in bot.js
const pysearch = require('../bboti/python-search');
class MyBot {
  // constructor...
  async onTurn(context) {
    // ...
    try {
      // 用await等待子进程完成,拿到结果
      const search_engine_answer = await pysearch.searchForRelevantDoc(context);
      // 此时context还处于onTurn的生命周期内,可以正常调用sendActivity
      await context.sendActivity(search_engine_answer);
    } catch (err) {
      // 处理可能的错误(比如子进程启动失败、Python脚本报错)
      console.error('Search failed:', err);
      await context.sendActivity('抱歉,搜索出现了问题,请稍后再试。');
    }
    // ...
  }
}

额外注意事项

  • 路径问题:用path.resolve(__dirname, '../path/to/file.py')代替相对路径,避免Node.js工作目录变化导致找不到Python脚本。
  • 错误处理:加入try/catch捕获异常,避免机器人崩溃,同时给用户友好的提示。
  • 长耗时脚本:如果Python脚本执行时间很长(超过15秒),可能会触发Bot Framework的turn超时,这种情况下需要考虑用异步任务队列处理,但一般简单的搜索脚本不会有这个问题。

内容的提问来源于stack exchange,提问作者Lady_Hangaku

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:49:11