AIエージェントでできること
AIエージェントを使えば、LLMが行うことができる文章を生成するタスク以外にもさまざまな作業を実行することができる。そして、世の中にはさまざまなAIエージェントのサービスがある。今回、LLMがweb検索やAPI呼び出しなどの機能を活用するために、「Function Calling」という機能を活用する。Function Callingは、LLMにtoolをあらかじめ与えておくと適切なtoolをLLMが選択するという機能である。
Function Calling Tool
今回はAIエージェントをlangchainで実装する。langchainにはコミュニティからさまざまなツールが提供されており、以下を参照するとweb検索や論文検索、自動化ワークフローの呼び出しなど多くのツールを確認できる。
しかし、このツール中に用意されたpython実行用のツール「ExecPython」を使いたいと思うとrizaioというサービスに登録しなければならず、システム運用で手元の環境中でスクリプトを実行したい場合などの用途で使うことができない。
そこで、今回は「pythonの実行」と「OSコマンドの実行」を手元の環境で実行できるツールを自作することにした。そして、これらのツールを使ってシステム運用の指示をLLMに与えると実行すべき運用手順が出力され、実行してよければ手元の環境でそのまま実行できるAIエージェントを作成する。システム運用ではほかにも実現すべき機能はたくさんあるが、今回は2つのツールでできることのみに絞る。追加機能が必要であればツールを追加すれば簡単にAIエージェントの機能を拡張できる。
システム運用AIエージェント
以下のフローチャートに沿ってColaboratory上でlanggraphを作成した。
Colaboratoryのコード
python実行ツールのコードは以下となる。pythonツールでは、入力されたpythonコードを実行し、実行した結果の標準出力とエラー出力を返却する。
class PythonExecTool(BaseTool):
"""A tool implementation to execute Python."""
name: str = "exec_python_local"
description: str = """Execute Python code to solve problems.
Input python code and get stdout and stderr of executed result.
"""
def __init__(self, **kwargs: Any) -> None:
super().__init__(**kwargs)
def _run(self, code: str):
return self.code_exec(code)
def code_exec(self, code, env_g = {}, env_l = {}):
@contextlib.contextmanager
def stdoutIO(stdout=None):
old = sys.stdout
if stdout is None:
stdout = StringIO()
sys.stdout = stdout
yield stdout
sys.stdout = old
res = {"output": "", "error": ""}
err_msg = ""
with stdoutIO() as exec_output_io:
try:
exec(code, env_g, env_l)
except Exception as err:
err_msg += str(traceback.format_exc())
res = {
"output": exec_output_io.getvalue(),
"error": err_msg,
}
return res
Shellコマンド実行ツールのコードは以下となる。Shellコマンドを実行したときの標準出力とエラー出力を返却する。
class ShellExecTool(BaseTool):
"""A tool implementation to execute shell command."""
name: str = "exec_shell_local"
description: str = """Execute shell command to solve problems.
Input shell command and get stdout and stderr of executed result.
"""
def __init__(self, **kwargs: Any) -> None:
super().__init__(**kwargs)
def _run(self, command: str):
return self.command_exec([command])
def command_exec(self, args: list[str], stdin = None):
if stdin is None:
proc_run = subprocess.run(args, capture_output=True, text=True, shell=True)
else:
proc_run = subprocess.run(args, stdin=stdin, capture_output=True, text=True, shell=True)
output = proc_run.stdout
error = proc_run.stderr
return {
"output": output,
"error": error,
}
結果
上記で実装したAIエージェントに以下のクエリを入力した。内容としては、/etc/hostsファイル中に「www.example.com」というエントリーがなければ、IPアドレス192.168.0.100でエントリーを追加する内容である。
I want to execute below steps.
1. Check whether "www.example.com" is written in /etc/hosts. If "www.example.com" is not written in /etc/hosts, write "www.example.com 192.168.0.100" in /etc/hosts.
2. Ping "www.example.com" and check ping is succeeded.
すると、以下の一連のツール実行確認のメッセージが出力された。
===[Execution]===
tool name: shell_tool
tool args: {'command': "grep -q 'www.example.com' /etc/hosts || echo 'www.example.com 192.168.0.100' | sudo tee -a /etc/hosts"}
-----
tool name: shell_tool
tool args: {'command': 'ping -c 4 www.example.com'}
-----
===[User check]===
code execution proceed? (True/False):
内容として正しいので、ここで「True」と入力すると一連のコマンドが実行される。
このように、簡単な運用手順を入力するとそこからOSコマンドが作成されることを確認できた。
他にも、以下のクエリを入力して実行すると、正しくpythonファイルとoutput.txtファイルが作成された。
I want to execute below steps.
1. Make file "test.py" in current directory.
2. Write python program in "test.py". Print 1 to 10 in this program.
3. Execute "test.py" and write output to output.txt.
今回作成したAIエージェントはpythonコードとOSコマンドを実行することしかできないが、マシン中でコマンドを実行したりファイルを確認させて調査したレポートを出力させたり日常のシステム運用に応用できそうだと思った。ほかにも内部システムのAPIを呼び出したりpdfを出力するなどの機能を追加したければツールとして追加するだけで実現できるので、langchainでは提供されていないツールでも簡単に作成でき、AIエージェントをより便利にりyできるとわかった。