diff --git a/docs/source/ko/_toctree.yml b/docs/source/ko/_toctree.yml index ddd73e71b..31741b4b5 100644 --- a/docs/source/ko/_toctree.yml +++ b/docs/source/ko/_toctree.yml @@ -14,8 +14,8 @@ # title: ๐Ÿ“Š Inspect your agent runs using telemetry # - local: tutorials/tools # title: ๐Ÿ› ๏ธ Tools - in-depth guide -# - local: tutorials/secure_code_execution -# title: ๐Ÿ›ก๏ธ Secure code execution + - local: tutorials/secure_code_execution + title: ๐Ÿ›ก๏ธ ์•ˆ์ „ํ•œ ์ฝ”๋“œ ์‹คํ–‰ - local: tutorials/memory title: ๐Ÿ“š ์—์ด์ „ํŠธ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ - title: Conceptual guides diff --git a/docs/source/ko/tutorials/secure_code_execution.md b/docs/source/ko/tutorials/secure_code_execution.md new file mode 100644 index 000000000..5bd07c948 --- /dev/null +++ b/docs/source/ko/tutorials/secure_code_execution.md @@ -0,0 +1,470 @@ +# ์•ˆ์ „ํ•œ ์ฝ”๋“œ ์‹คํ–‰[[secure-code-execution]] + +[[open-in-colab]] + +> [!TIP] +> ์—์ด์ „ํŠธ ๋นŒ๋“œ์— ์ต์ˆ™ํ•˜์ง€ ์•Š์œผ์‹œ๋‹ค๋ฉด, ๋จผ์ € [์—์ด์ „ํŠธ ์†Œ๊ฐœ](../conceptual_guides/intro_agents)์™€ [smolagents ๊ฐ€์ด๋“œ ํˆฌ์–ด](../guided_tour)๋ฅผ ์ฝ์–ด๋ณด์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค. + +### ์ฝ”๋“œ ์—์ด์ „ํŠธ[[code-agents]] + +[์—ฌ๋Ÿฌ](https://huggingface.co/papers/2402.01030) [์—ฐ๊ตฌ](https://huggingface.co/papers/2411.01747) [๋…ผ๋ฌธ](https://huggingface.co/papers/2401.00812)์— ๋”ฐ๋ฅด๋ฉด, LLM์ด ์ž์‹ ์˜ ํ–‰๋™(๋„๊ตฌ ํ˜ธ์ถœ)์„ ์ฝ”๋“œ๋กœ ์ž‘์„ฑํ•˜๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ด ํ˜„์žฌ์˜ ํ‘œ์ค€ ๋„๊ตฌ ํ˜ธ์ถœ ํ˜•์‹๋ณด๋‹ค ํ›จ์”ฌ ๋” ํšจ๊ณผ์ ์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ ์—…๊ณ„ ํ‘œ์ค€์€ โ€˜๋„๊ตฌ ์ด๋ฆ„๊ณผ ์‚ฌ์šฉํ•  ์ธ์ˆ˜๋ฅผ JSON ํ˜•ํƒœ๋กœ ๊ธฐ์ˆ ํ•˜๋Š”โ€™ ๋‹ค์–‘ํ•œ ๋ณ€ํ˜• ๋ฐฉ์‹์„ ๋”ฐ๋ฅด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. + +์™œ ์ฝ”๋“œ๊ฐ€ ๋” ๋‚˜์„๊นŒ์š”? ์šฐ๋ฆฌ๋Š” ์ปดํ“จํ„ฐ๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋Š” ์ž‘์—…์„ ์ž˜ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ํŠน๋ณ„ํžˆ ์ฝ”๋“œ ์–ธ์–ด๋ฅผ ๋งŒ๋“ค์—ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ JSON ์Šค๋‹ˆํŽซ์ด ๋” ๋‚˜์€ ๋ฐฉ๋ฒ•์ด์—ˆ๋‹ค๋ฉด, ์ด ํŒจํ‚ค์ง€๋Š” JSON์œผ๋กœ ์ž‘์„ฑ๋์„ ๊ฒƒ์ด๊ณ , ์•„๋งˆ ์•…๋งˆ๊ฐ€ ์šฐ๋ฆฌ๋ฅผ ๋น„์›ƒ์—ˆ์„ ๊ฒ๋‹ˆ๋‹ค. + +์ฝ”๋“œ๋Š” ์ปดํ“จํ„ฐ์—์„œ์˜ ์ž‘์—…์„ ํ‘œํ˜„ํ•˜๋Š” ๋” ๋‚˜์€ ๋ฐฉ๋ฒ•์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. +- **๊ตฌ์„ฑ ๊ฐ€๋Šฅ์„ฑ:** ํŒŒ์ด์ฌ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ JSON ์ž‘์—…์„ ์ค‘์ฒฉํ•˜๊ฑฐ๋‚˜ ๋‚˜์ค‘์— ์žฌ์‚ฌ์šฉํ•  JSON ์ž‘์—… ์„ธํŠธ๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”? +- **๊ฐ์ฒด ๊ด€๋ฆฌ:** `generate_image`์™€ ๊ฐ™์€ ์ž‘์—…์˜ ์ถœ๋ ฅ์„ JSON์— ์–ด๋–ป๊ฒŒ ์ €์žฅํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”? +- **์ผ๋ฐ˜์„ฑ:** ์ฝ”๋“œ๋Š” ์ปดํ“จํ„ฐ๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ๊ฒƒ์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ‘œํ˜„ํ•˜๋„๋ก ๋งŒ๋“ค์–ด์กŒ์Šต๋‹ˆ๋‹ค. +- **LLM ํ›ˆ๋ จ ์ฝ”ํผ์Šค์—์„œ์˜ ํ‘œํ˜„:** LLM ํ›ˆ๋ จ ์ฝ”ํผ์Šค์— ์ด๋ฏธ ์ˆ˜๋งŽ์€ ์–‘์งˆ์˜ ์ž‘์—…์ด ํฌํ•จ๋˜์–ด ์žˆ๋‹ค๋Š” ํ•˜๋Š˜์˜ ์ถ•๋ณต์„ ํ™œ์šฉํ•˜์ง€ ์•Š์„ ์ด์œ ๊ฐ€ ์žˆ์„๊นŒ์š”? + +์ด๋Š” [Executable Code Actions Elicit Better LLM Agents](https://huggingface.co/papers/2402.01030)์—์„œ ๊ฐ€์ ธ์˜จ ์•„๋ž˜ ๊ทธ๋ฆผ์— ์ž˜ ๋‚˜ํƒ€๋‚˜ ์žˆ์Šต๋‹ˆ๋‹ค. + + + +์ด๊ฒƒ์ด ์šฐ๋ฆฌ๊ฐ€ ์ฝ”๋“œ ์—์ด์ „ํŠธ(์ด ๊ฒฝ์šฐ์—๋Š” ํŒŒ์ด์ฌ ์—์ด์ „ํŠธ)๋ฅผ ์ œ์•ˆํ•˜๋Š” ๋ฐ ์ค‘์ ์„ ๋‘๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๊ณง ์•ˆ์ „ํ•œ ํŒŒ์ด์ฌ ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋ฅผ ๊ตฌ์ถ•ํ•˜๊ธฐ ์œ„ํ•ด ๋” ๋งŽ์€ ๋…ธ๋ ฅ์ด ํ•„์š”ํ•จ์„ ์˜๋ฏธํ–ˆ์Šต๋‹ˆ๋‹ค. + +### ๋กœ์ปฌ ์ฝ”๋“œ ์‹คํ–‰??[[local-code-execution]] + +๊ธฐ๋ณธ์ ์œผ๋กœ `CodeAgent`๋Š” LLM์ด ์ƒ์„ฑํ•œ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉ์ž์˜ ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. + +์ด๋Š” ๋ณธ์งˆ์ ์œผ๋กœ ์œ„ํ—˜ํ•˜๋ฉฐ, LLM์ด ์ƒ์„ฑํ•œ ์ฝ”๋“œ๋Š” ์‚ฌ์šฉ์ž์˜ ํ™˜๊ฒฝ์„ ์†์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + +์•…์„ฑ ์ฝ”๋“œ ์‹คํ–‰์€ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฐฉ์‹์œผ๋กœ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- **๋‹จ์ˆœ LLM ์˜ค๋ฅ˜:** LLM์€ ์•„์ง ์™„๋ฒฝํ•˜์ง€ ์•Š์œผ๋ฉฐ ๋„์›€์„ ์ฃผ๋ ค๋Š” ๊ณผ์ •์—์„œ ์˜๋„์น˜ ์•Š๊ฒŒ ํ•ด๋กœ์šด ๋ช…๋ น์–ด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์œ„ํ—˜์€ ๋‚ฎ์ง€๋งŒ LLM์ด ์ž ์žฌ์ ์œผ๋กœ ์œ„ํ—˜ํ•œ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ ค ์‹œ๋„ํ•œ ์‚ฌ๋ก€๊ฐ€ ์‹ค์ œ๋กœ ๊ด€์ฐฐ๋œ ๋ฐ” ์žˆ์Šต๋‹ˆ๋‹ค. +- **๊ณต๊ธ‰๋ง ๊ณต๊ฒฉ:** ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๊ฑฐ๋‚˜ ์†์ƒ๋œ LLM์„ ์‹คํ–‰ํ•˜๋ฉด ์‹œ์Šคํ…œ์ด ์œ ํ•ดํ•œ ์ฝ”๋“œ ์ƒ์„ฑ์— ๋…ธ์ถœ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•ˆ์ „ํ•œ ์ถ”๋ก  ์ธํ”„๋ผ์—์„œ ์ž˜ ์•Œ๋ ค์ง„ ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•  ๋•Œ ์ด ์œ„ํ—˜์€ ๋งค์šฐ ๋‚ฎ์ง€๋งŒ, ์ด๋ก ์ ์ธ ๊ฐ€๋Šฅ์„ฑ์€ ๋‚จ์•„ ์žˆ์Šต๋‹ˆ๋‹ค. +- **ํ”„๋กฌํ”„ํŠธ ์ธ์ ์…˜:** ์›น์„ ํƒ์ƒ‰ํ•˜๋Š” ์—์ด์ „ํŠธ๊ฐ€ ์œ ํ•ดํ•œ ์ง€์นจ์ด ํฌํ•จ๋œ ์•…์„ฑ ์›น์‚ฌ์ดํŠธ์— ๋„๋‹ฌํ•ด ์—์ด์ „ํŠธ์˜ ๋ฉ”๋ชจ๋ฆฌ์— ๊ณต๊ฒฉ์„ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- **๊ณต๊ฐœ์ ์œผ๋กœ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ์—์ด์ „ํŠธ ์•…์šฉ:** ๋Œ€์ค‘์—๊ฒŒ ๋…ธ์ถœ๋œ ์—์ด์ „ํŠธ๋Š” ์•…์˜์ ์ธ ํ–‰์œ„์ž์— ์˜ํ•ด ์•…์šฉ๋˜์–ด ์œ ํ•ดํ•œ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ณต๊ฒฉ์ž๋Š” ์—์ด์ „ํŠธ์˜ ์‹คํ–‰ ๋Šฅ๋ ฅ์„ ์•…์šฉํ•˜๊ธฐ ์œ„ํ•ด ์ ๋Œ€์ ์ธ ์ž…๋ ฅ์„ ๋งŒ๋“ค์–ด ์˜๋„ํ•˜์ง€ ์•Š์€ ๊ฒฐ๊ณผ๋ฅผ ์ดˆ๋ž˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +์•…์„ฑ ์ฝ”๋“œ๊ฐ€ ์šฐ๋ฐœ์ ์ด๋“  ์˜๋„์ ์ด๋“  ์‹คํ–‰๋˜๋ฉด ํŒŒ์ผ ์‹œ์Šคํ…œ์ด ์†์ƒ๋˜๊ณ , ๋กœ์ปฌ ๋˜๋Š” ํด๋ผ์šฐ๋“œ ๋ฆฌ์†Œ์Šค๊ฐ€ ์•…์šฉ๋˜๋ฉฐ, API ์„œ๋น„์Šค๊ฐ€ ๋‚จ์šฉ๋˜๊ณ , ์‹ฌ์ง€์–ด ๋„คํŠธ์›Œํฌ ๋ณด์•ˆ๊นŒ์ง€ ์œ„ํ˜‘๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + +[์—์ด์ „์‹œ ์ŠคํŽ™ํŠธ๋Ÿผ](../conceptual_guides/intro_agents)์—์„œ ์ฝ”๋“œ ์—์ด์ „ํŠธ๋Š” ๋‹ค๋ฅธ ๋œ ์—์ด์ „ํŠธ์ ์ธ ์„ค์ •์— ๋น„ํ•ด ์‹œ์Šคํ…œ ๋‚ด์—์„œ LLM์—๊ฒŒ ํ›จ์”ฌ ๋” ๋†’์€ ์ˆ˜์ค€์˜ ์—์ด์ „์‹œ๋ฅผ ๋ถ€์—ฌํ•œ๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๊ณง ๋” ๋†’์€ ์ˆ˜์ค€์˜ ์œ„ํ—˜์„ ์ˆ˜๋ฐ˜ํ•ฉ๋‹ˆ๋‹ค. + +๋”ฐ๋ผ์„œ ๋ณด์•ˆ์— ๊ฐ๋ณ„ํ•œ ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. + +๋” ๊ฐ•๋ ฅํ•œ ๋ณด์•ˆ์„ ์œ„ํ•ด, ์„ค์ • ๋น„์šฉ์€ ๋‹ค์†Œ ๋†’์ง€๋งŒ ๋ณด๋‹ค ๋†’์€ ์ˆ˜์ค€์˜ ๋ณดํ˜ธ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋‹ค์–‘ํ•œ ์กฐ์น˜๋ฅผ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค. + +์–ด๋–ค ํ•ด๊ฒฐ์ฑ…๋„ 100% ์•ˆ์ „ํ•˜์ง€ ์•Š๋‹ค๋Š” ์ ์„ ๋ช…์‹ฌํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค. + + + +### ๋กœ์ปฌ ํŒŒ์ด์ฌ ์‹คํ–‰๊ธฐ[[our-local-python-executor]] + +์ฒซ ๋ฒˆ์งธ ๋ณด์•ˆ ๊ณ„์ธต์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด, ์ผ๋ฐ˜ ํŒŒ์ด์ฌ ์ธํ„ฐํ”„๋ฆฌํ„ฐ์—์„œ `smolagents`์˜ ์ฝ”๋“œ ์‹คํ–‰๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. +์šฐ๋ฆฌ๋Š” ๋” ์•ˆ์ „ํ•œ `LocalPythonExecutor`๋ฅผ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ ๊ตฌ์ถ•ํ–ˆ์Šต๋‹ˆ๋‹ค. + +์ •ํ™•ํžˆ ๋งํ•˜๋ฉด, ์ด ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋Š” ์ฝ”๋“œ์—์„œ ์ถ”์ƒ ๊ตฌ๋ฌธ ํŠธ๋ฆฌ(AST)๋ฅผ ๊ฐ€์ ธ์™€์„œ ์ด๋ฅผ ์—ฐ์‚ฐ ๋‹จ์œ„๋กœ ์‹คํ–‰ํ•˜๋ฉฐ ํ•ญ์ƒ ํŠน์ • ๊ทœ์น™์„ ๋”ฐ๋ฅด๋„๋ก ํ•ฉ๋‹ˆ๋‹ค +- ๊ธฐ๋ณธ์ ์œผ๋กœ, ์‚ฌ์šฉ์ž๊ฐ€ ์Šน์ธ ๋ชฉ๋ก์— ๋ช…์‹œ์ ์œผ๋กœ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๋Š” ํ•œ import๋Š” ํ—ˆ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. +- ๋˜ํ•œ, ํ•˜์œ„ ๋ชจ๋“ˆ์— ๋Œ€ํ•œ ์ ‘๊ทผ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋น„ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์œผ๋ฉฐ, ๊ฐ ํ•˜์œ„ ๋ชจ๋“ˆ๋„ import ๋ชฉ๋ก์—์„œ ๋ช…์‹œ์ ์œผ๋กœ ์Šน์ธ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋˜๋Š” ์˜ˆ๋ฅผ ๋“ค์–ด `numpy.*`๋ฅผ ์ „๋‹ฌํ•˜์—ฌ `numpy`์™€ `numpy.random` ๋˜๋Š” `numpy.a.b`์™€ ๊ฐ™์€ ๋ชจ๋“  ํ•˜์œ„ ํŒจํ‚ค์ง€๋ฅผ ํ—ˆ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + - `random`๊ณผ ๊ฐ™์ด ๊ฒ‰๋ณด๊ธฐ์— ๋ฌดํ•ดํ•ด ๋ณด์ด๋Š” ์ผ๋ถ€ ํŒจํ‚ค์ง€๋„ `random._os`์—์„œ์ฒ˜๋Ÿผ ์ž ์žฌ์ ์œผ๋กœ ์œ ํ•ดํ•œ ํ•˜์œ„ ๋ชจ๋“ˆ์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์— ์œ ์˜ํ•˜์„ธ์š”. +- ์ฒ˜๋ฆฌ๋˜๋Š” ๊ธฐ๋ณธ ์—ฐ์‚ฐ์˜ ์ด ํšŸ์ˆ˜๋Š” ๋ฌดํ•œ ๋ฃจํ”„์™€ ๋ฆฌ์†Œ์Šค ํŒฝ์ฐฝ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์ œํ•œ๋ฉ๋‹ˆ๋‹ค. +- ์‚ฌ์šฉ์ž ์ •์˜ ์ธํ„ฐํ”„๋ฆฌํ„ฐ์— ๋ช…์‹œ์ ์œผ๋กœ ์ •์˜๋˜์ง€ ์•Š์€ ๋ชจ๋“  ์—ฐ์‚ฐ์€ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. + +๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ด๋Ÿฌํ•œ ์•ˆ์ „์žฅ์น˜๋ฅผ ์‹œํ—˜ํ•ด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + +```py +from smolagents.local_python_executor import LocalPythonExecutor + +# ์‚ฌ์šฉ์ž ์ •์˜ ์‹คํ–‰๊ธฐ ์„ค์ •, "numpy" ํŒจํ‚ค์ง€ ์Šน์ธ +custom_executor = LocalPythonExecutor(["numpy"]) + +# ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ๊ฐ€๋…์„ฑ์ด ์ข‹๊ฒŒ ์ถœ๋ ฅํ•˜๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ +def run_capture_exception(command: str): + try: + custom_executor(harmful_command) + except Exception as e: + print("ERROR:\n", e) + +# ์ •์˜๋˜์ง€ ์•Š์€ ๋ช…๋ น์–ด๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š์Œ +harmful_command="!echo Bad command" +run_capture_exception(harmful_command) +# >>> ERROR: invalid syntax (, line 1) + + +# os์™€ ๊ฐ™์€ import๋Š” `additional_authorized_imports`์— ๋ช…์‹œ์ ์œผ๋กœ ์ถ”๊ฐ€๋˜์ง€ ์•Š๋Š” ํ•œ ์ˆ˜ํ–‰๋˜์ง€ ์•Š์Œ +harmful_command="import os; exit_code = os.system('echo Bad command')" +run_capture_exception(harmful_command) +# >>> ERROR: Code execution failed at line 'import os' due to: InterpreterError: Import of os is not allowed. Authorized imports are: ['statistics', 'numpy', 'itertools', 'time', 'queue', 'collections', 'math', 'random', 're', 'datetime', 'stat', 'unicodedata'] + +# ์Šน์ธ๋œ import์—์„œ๋„ ์ž ์žฌ์ ์œผ๋กœ ์œ ํ•ดํ•œ ํŒจํ‚ค์ง€๋Š” import๋˜์ง€ ์•Š์Œ +harmful_command="import random; random._os.system('echo Bad command')" +run_capture_exception(harmful_command) +# >>> ERROR: Code execution failed at line 'random._os.system('echo Bad command')' due to: InterpreterError: Forbidden access to module: os + +# ๋ฌดํ•œ ๋ฃจํ”„๋Š” N๋ฒˆ์˜ ์—ฐ์‚ฐ ํ›„ ์ค‘๋‹จ๋จ +harmful_command=""" +while True: + pass +""" +run_capture_exception(harmful_command) +# >>> ERROR: Code execution failed at line 'while True: pass' due to: InterpreterError: Maximum number of 1000000 iterations in While loop exceeded +``` + +์ด๋Ÿฌํ•œ ์•ˆ์ „์žฅ์น˜ ๋•๋ถ„์— ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋Š” ๋” ์•ˆ์ „ํ•˜๊ฒŒ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +๋‹ค์–‘ํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋ฅผ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ ์‚ฌ์šฉ์ž ํ™˜๊ฒฝ์— ์–ด๋– ํ•œ ์†์ƒ๋„ ๊ด€์ฐฐ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. + +> [!WARNING] +> ๋กœ์ปฌ ํŒŒ์ด์ฌ ์ƒŒ๋“œ๋ฐ•์Šค ํ™˜๊ฒฝ์€ ๋ณธ์งˆ์ ์œผ๋กœ ์™„์ „ํ•œ ์•ˆ์ „์„ฑ์„ ๋ณด์žฅํ•  ์ˆ˜ ์—†๋‹ค๋Š” ์ ์„ ์ธ์‹ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์ €ํฌ ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋Š” ํ‘œ์ค€ ํŒŒ์ด์ฌ ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋ณด๋‹ค ์•ˆ์ „์„ฑ์ด ํฌ๊ฒŒ ํ–ฅ์ƒ๋˜์—ˆ์ง€๋งŒ, ์˜์ง€๊ฐ€ ํ™•๊ณ ํ•œ ๊ณต๊ฒฉ์ž๋‚˜ ์•…์˜์ ์œผ๋กœ ๋ฏธ์„ธ ์กฐ์ •๋œ LLM์ด ์ทจ์•ฝ์ ์„ ์ฐพ์•„ ์‚ฌ์šฉ์ž ํ™˜๊ฒฝ์— ํ”ผํ•ด๋ฅผ ์ค„ ๊ฐ€๋Šฅ์„ฑ์€ ์—ฌ์ „ํžˆ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. +> +> ์˜ˆ๋ฅผ ๋“ค์–ด, `Pillow`์™€ ๊ฐ™์€ ํŒจํ‚ค์ง€๊ฐ€ ์ด๋ฏธ์ง€๋ฅผ ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ—ˆ์šฉํ•œ ๊ฒฝ์šฐ, LLM์€ ํ•˜๋“œ ๋“œ๋ผ์ด๋ธŒ๋ฅผ ๊ฐ€๋“ ์ฑ„์šธ ์ˆ˜์ฒœ ๊ฐœ์˜ ๋Œ€์šฉ๋Ÿ‰ ์ด๋ฏธ์ง€ ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๊ณ ๊ธ‰ ํƒˆ์ถœ ๊ธฐ์ˆ ์€ ์Šน์ธ๋œ ํŒจํ‚ค์ง€์˜ ๋” ๊นŠ์€ ์ทจ์•ฝ์ ์„ ์•…์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +> +> LLM์ด ์ƒ์„ฑํ•œ ์ฝ”๋“œ๋ฅผ ๋กœ์ปฌ ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์€ ํ•ญ์ƒ ์œ„ํ—˜์„ ๋‚ดํฌํ•ฉ๋‹ˆ๋‹ค. ์ง„์ •์œผ๋กœ ๊ฐ•๋ ฅํ•œ ๋ณด์•ˆ ๊ฒฉ๋ฆฌ๋ฅผ ํ†ตํ•ด LLM ์ƒ์„ฑ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์€ ์•„๋ž˜์— ์ž์„ธํžˆ ์„ค๋ช…๋œ E2B๋‚˜ Docker์™€ ๊ฐ™์€ ์›๊ฒฉ ์‹คํ–‰ ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. + +์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์ถ”๋ก  ์ œ๊ณต์—…์ฒด์˜ ์ž˜ ์•Œ๋ ค์ง„ LLM์„ ์‚ฌ์šฉํ•  ๋•Œ ์•…์˜์ ์ธ ๊ณต๊ฒฉ์˜ ์œ„ํ—˜์€ ๋‚ฎ์ง€๋งŒ 0์€ ์•„๋‹™๋‹ˆ๋‹ค. +๋ณด์•ˆ ์ˆ˜์ค€์ด ๋†’์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด๋‚˜ ์‹ ๋ขฐ๋„๊ฐ€ ๋‚ฎ์€ ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, ์›๊ฒฉ ์‹คํ–‰ ์ƒŒ๋“œ๋ฐ•์Šค ์‚ฌ์šฉ์„ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. + +## ์•ˆ์ „ํ•œ ์ฝ”๋“œ ์‹คํ–‰์„ ์œ„ํ•œ ์ƒŒ๋“œ๋ฐ•์Šค ์ ‘๊ทผ ๋ฐฉ์‹[[sandbox-approaches-for-secure-code-execution]] + +์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” AI ์—์ด์ „ํŠธ๋กœ ์ž‘์—…ํ•  ๋•Œ ๋ณด์•ˆ์€ ๊ฐ€์žฅ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. smolagents์—์„œ ์ฝ”๋“œ ์‹คํ–‰์„ ์ƒŒ๋“œ๋ฐ•์‹ฑํ•˜๋Š” ๋ฐ์—๋Š” ๋‘ ๊ฐ€์ง€ ์ฃผ์š” ์ ‘๊ทผ ๋ฐฉ์‹์ด ์žˆ์œผ๋ฉฐ, ๊ฐ๊ฐ ๋‹ค๋ฅธ ๋ณด์•ˆ ์†์„ฑ๊ณผ ๊ธฐ๋Šฅ์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค: + + +![์ƒŒ๋“œ๋ฐ•์Šค ์ ‘๊ทผ ๋ฐฉ์‹ ๋น„๊ต](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/smolagents/sandboxed_execution.png) + +1. **๊ฐœ๋ณ„ ์ฝ”๋“œ ์Šค๋‹ˆํŽซ์„ ์ƒŒ๋“œ๋ฐ•์Šค์—์„œ ์‹คํ–‰**: ์ด ์ ‘๊ทผ ๋ฐฉ์‹(๋‹ค์ด์–ด๊ทธ๋žจ ์™ผ์ชฝ)์€ ์—์ด์ „ํŠธ๊ฐ€ ์ƒ์„ฑํ•œ ํŒŒ์ด์ฌ ์ฝ”๋“œ ์Šค๋‹ˆํŽซ๋งŒ ์ƒŒ๋“œ๋ฐ•์Šค์—์„œ ์‹คํ–‰ํ•˜๊ณ  ๋‚˜๋จธ์ง€ ์—์ด์ „ํŠธ ์‹œ์Šคํ…œ์€ ๋กœ์ปฌ ํ™˜๊ฒฝ์— ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. `executor_type="e2b"`, `executor_type="modal"` ๋˜๋Š” +`executor_type="docker"`๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„ค์ •ํ•˜๊ธฐ๊ฐ€ ๋” ๊ฐ„๋‹จํ•˜์ง€๋งŒ, ๋‹ค์ค‘ ์—์ด์ „ํŠธ๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š์œผ๋ฉฐ ์—ฌ์ „ํžˆ ํ™˜๊ฒฝ๊ณผ ์ƒŒ๋“œ๋ฐ•์Šค ๊ฐ„์— ์ƒํƒœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. + +2. **์ „์ฒด ์—์ด์ „ํŠธ ์‹œ์Šคํ…œ์„ ์ƒŒ๋“œ๋ฐ•์Šค์—์„œ ์‹คํ–‰**: ์ด ์ ‘๊ทผ ๋ฐฉ์‹(๋‹ค์ด์–ด๊ทธ๋žจ ์˜ค๋ฅธ์ชฝ)์€ ์—์ด์ „ํŠธ, ๋ชจ๋ธ, ๋„๊ตฌ๋ฅผ ํฌํ•จํ•œ ์ „์ฒด ์—์ด์ „ํŠธ ์‹œ์Šคํ…œ์„ ์ƒŒ๋“œ๋ฐ•์Šค ํ™˜๊ฒฝ ๋‚ด์—์„œ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋” ๋‚˜์€ ๊ฒฉ๋ฆฌ๋ฅผ ์ œ๊ณตํ•˜์ง€๋งŒ ๋” ๋งŽ์€ ์ˆ˜๋™ ์„ค์ •์ด ํ•„์š”ํ•˜๋ฉฐ, ๋ฏผ๊ฐํ•œ ์ž๊ฒฉ ์ฆ๋ช…(API ํ‚ค ๋“ฑ)์„ ์ƒŒ๋“œ๋ฐ•์Šค ํ™˜๊ฒฝ์œผ๋กœ ์ „๋‹ฌํ•ด์•ผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + +์ด ๊ฐ€์ด๋“œ์—์„œ๋Š” ์—์ด์ „ํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์œ„ํ•ด ๋‘ ๊ฐ€์ง€ ์œ ํ˜•์˜ ์ƒŒ๋“œ๋ฐ•์Šค ์ ‘๊ทผ ๋ฐฉ์‹์„ ์„ค์ •ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. + +### E2B ์„ค์ •[[e2b-setup]] + +#### ์„ค์น˜[[installation]] + +1. [e2b.dev](https://e2b.dev)์—์„œ E2B ๊ณ„์ •์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. +2. ํ•„์š”ํ•œ ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค: +```bash +pip install 'smolagents[e2b]' +``` + +#### E2B์—์„œ ์—์ด์ „ํŠธ ์‹คํ–‰ํ•˜๊ธฐ: ๋น ๋ฅธ ์‹œ์ž‘[[running-your-agent-in-e2b-quick-start]] + +E2B ์ƒŒ๋“œ๋ฐ•์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ„๋‹จํ•œ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์—์ด์ „ํŠธ ์ดˆ๊ธฐํ™”์— `executor_type="e2b"`๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค: + +```py +from smolagents import InferenceClientModel, CodeAgent + +with CodeAgent(model=InferenceClientModel(), tools=[], executor_type="e2b") as agent: + agent.run("100๋ฒˆ์งธ ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜๋ฅผ ์•Œ๋ ค์ค„ ์ˆ˜ ์žˆ๋‚˜์š”?") +``` + +> [!TIP] +> ์—์ด์ „ํŠธ๋ฅผ ์ปจํ…์ŠคํŠธ ๊ด€๋ฆฌ์ž(`with` ๋ฌธ)๋กœ ์‚ฌ์šฉํ•˜๋ฉด ์—์ด์ „ํŠธ๊ฐ€ ์ž‘์—…์„ ์™„๋ฃŒํ•œ ์งํ›„ E2B ์ƒŒ๋“œ๋ฐ•์Šค๊ฐ€ ์ž์› ํ•ด์ œ ๋ฐ ์ •๋ฆฌ๊ฐ€ ์ž๋™์œผ๋กœ ์ˆ˜ํ–‰๋˜๋„๋ก ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค. +> ๋˜๋Š” ์—์ด์ „ํŠธ์˜ `cleanup()` ๋ฉ”์†Œ๋“œ๋ฅผ ์ˆ˜๋™์œผ๋กœ ํ˜ธ์ถœํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. + +์ด ์†”๋ฃจ์…˜์€ ๊ฐ `agent.run()` ์‹œ์ž‘ ์‹œ ์—์ด์ „ํŠธ ์ƒํƒœ๋ฅผ ์„œ๋ฒ„๋กœ ๋ณด๋ƒ…๋‹ˆ๋‹ค. +๊ทธ๋Ÿฐ ๋‹ค์Œ ๋กœ์ปฌ ํ™˜๊ฒฝ์—์„œ ๋ชจ๋ธ์ด ํ˜ธ์ถœ๋˜์ง€๋งŒ, ์ƒ์„ฑ๋œ ์ฝ”๋“œ๋Š” ์‹คํ–‰์„ ์œ„ํ•ด ์ƒŒ๋“œ๋ฐ•์Šค๋กœ ์ „์†ก๋˜๊ณ  ์ถœ๋ ฅ๋งŒ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค. + +์ด๋Š” ์•„๋ž˜ ๊ทธ๋ฆผ์— ์„ค๋ช…๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. + +

+ sandboxed code execution +

+ +ํ•˜์ง€๋งŒ [๊ด€๋ฆฌํ˜• ์—์ด์ „ํŠธ](../examples/multiagents)์— ๋Œ€ํ•œ ๋ชจ๋“  ํ˜ธ์ถœ์€ ๋ชจ๋ธ ํ˜ธ์ถœ์„ ํ•„์š”๋กœ ํ•˜๋Š”๋ฐ, ๋น„๋ฐ€ ์ •๋ณด๋ฅผ ์›๊ฒฉ ์ƒŒ๋“œ๋ฐ•์Šค๋กœ ์ „์†กํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋ธ ํ˜ธ์ถœ์— ์ž๊ฒฉ ์ฆ๋ช…์ด ๋ถ€์กฑํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. +๋”ฐ๋ผ์„œ ์ด ์†”๋ฃจ์…˜์€ ๋” ๋ณต์žกํ•œ ๋‹ค์ค‘ ์—์ด์ „ํŠธ ์„ค์ •์—์„œ๋Š” ์•„์ง ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. + +#### E2B์—์„œ ์—์ด์ „ํŠธ ์‹คํ–‰ํ•˜๊ธฐ: ๋‹ค์ค‘ ์—์ด์ „ํŠธ[[running-your-agent-in-e2b-multi-agents]] + +E2B ์ƒŒ๋“œ๋ฐ•์Šค์—์„œ ๋‹ค์ค‘ ์—์ด์ „ํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด E2B ๋‚ด์—์„œ ์—์ด์ „ํŠธ๋ฅผ ์™„์ „ํžˆ ์‹คํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. + +๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. + +```python +from e2b_code_interpreter import Sandbox +import os + +# ์ƒŒ๋“œ๋ฐ•์Šค ์ƒ์„ฑ +sandbox = Sandbox() + +# ํ•„์š”ํ•œ ํŒจํ‚ค์ง€ ์„ค์น˜ +sandbox.commands.run("pip install smolagents") + +def run_code_raise_errors(sandbox, code: str, verbose: bool = False) -> str: + execution = sandbox.run_code( + code, + envs={'HF_TOKEN': os.getenv('HF_TOKEN')} + ) + if execution.error: + execution_logs = "\n".join([str(log) for log in execution.logs.stdout]) + logs = execution_logs + logs += execution.error.traceback + raise ValueError(logs) + return "\n".join([str(log) for log in execution.logs.stdout]) + +# ์—์ด์ „ํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ •์˜ +agent_code = """ +import os +from smolagents import CodeAgent, InferenceClientModel + +# ์—์ด์ „ํŠธ ์ดˆ๊ธฐํ™” +agent = CodeAgent( + model=InferenceClientModel(token=os.getenv("HF_TOKEN"), provider="together"), + tools=[], + name="coder_agent", + description="์ด ์—์ด์ „ํŠธ๋Š” ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์–ด๋ ค์šด ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ฌธ์ œ๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค." +) + +manager_agent = CodeAgent( + model=InferenceClientModel(token=os.getenv("HF_TOKEN"), provider="together"), + tools=[], + managed_agents=[agent], +) + +# ์—์ด์ „ํŠธ ์‹คํ–‰ +response = manager_agent.run("20๋ฒˆ์งธ ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜๋Š” ๋ฌด์—‡์ธ๊ฐ€์š”?") +print(response) +""" + +# ์ƒŒ๋“œ๋ฐ•์Šค์—์„œ ์—์ด์ „ํŠธ ์ฝ”๋“œ ์‹คํ–‰ +execution_logs = run_code_raise_errors(sandbox, agent_code) +print(execution_logs) +``` + +### Modal ์„ค์ •[[modal-setup]] + +#### ์„ค์น˜[[installation]] + +1. [modal.com](https://modal.com/signup)์—์„œ Modal ๊ณ„์ •์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. +2. ํ•„์š”ํ•œ ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค: +```bash +pip install 'smolagents[modal]' +``` + +#### Modal์—์„œ ์—์ด์ „ํŠธ ์‹คํ–‰ํ•˜๊ธฐ: ๋น ๋ฅธ ์‹œ์ž‘[[running-your-agent-in-modal-quick-start]] + +Modal ์ƒŒ๋“œ๋ฐ•์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ„๋‹จํ•œ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์—์ด์ „ํŠธ ์ดˆ๊ธฐํ™”์— `executor_type="modal"`์„ ์ถ”๊ฐ€ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค: + +```py +from smolagents import InferenceClientModel, CodeAgent + +with CodeAgent(model=InferenceClientModel(), tools=[], executor_type="modal") as agent: + agent.run("42๋ฒˆ์งธ ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜๋Š” ๋ฌด์—‡์ธ๊ฐ€์š”?") +``` + +> [!TIP] +> ์—์ด์ „ํŠธ๋ฅผ ์ปจํ…์ŠคํŠธ ๊ด€๋ฆฌ์ž(`with` ๋ฌธ)๋กœ ์‚ฌ์šฉํ•˜๋ฉด ์—์ด์ „ํŠธ๊ฐ€ ์ž‘์—…์„ ์™„๋ฃŒํ•œ ์งํ›„ Modal ์ƒŒ๋“œ๋ฐ•์Šค๊ฐ€ ์ •๋ฆฌ๋˜๋„๋ก ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค. +> ๋˜๋Š” ์—์ด์ „ํŠธ์˜ `cleanup()` ๋ฉ”์†Œ๋“œ๋ฅผ ์ˆ˜๋™์œผ๋กœ ํ˜ธ์ถœํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. + +`InferenceClientModel`์—์„œ ์ƒ์„ฑ๋œ ์—์ด์ „ํŠธ ์ƒํƒœ์™€ ์ฝ”๋“œ๋Š” Modal ์ƒŒ๋“œ๋ฐ•์Šค๋กœ ์ „์†ก๋˜์–ด ์•ˆ์ „ํ•˜๊ฒŒ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + +### Docker ์„ค์ •[[docker-setup]] + +#### ์„ค์น˜[[installation]] + +1. [์‹œ์Šคํ…œ์— Docker ์„ค์น˜ํ•˜๊ธฐ](https://docs.docker.com/get-started/get-docker/) +2. ํ•„์š”ํ•œ ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค. +```bash +pip install 'smolagents[docker]' +``` + +#### Docker์—์„œ ์—์ด์ „ํŠธ ์‹คํ–‰ํ•˜๊ธฐ: ๋น ๋ฅธ ์‹œ์ž‘[[running-your-agent-in-docker-quick-start]] + +์œ„์˜ E2B ์ƒŒ๋“œ๋ฐ•์Šค์™€ ์œ ์‚ฌํ•˜๊ฒŒ, Docker๋ฅผ ๋น ๋ฅด๊ฒŒ ์‹œ์ž‘ํ•˜๋ ค๋ฉด ์—์ด์ „ํŠธ ์ดˆ๊ธฐํ™”์— `executor_type="docker"`๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. + +```py +from smolagents import InferenceClientModel, CodeAgent + +with CodeAgent(model=InferenceClientModel(), tools=[], executor_type="docker") as agent: + agent.run("100๋ฒˆ์งธ ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜๋ฅผ ์•Œ๋ ค์ค„ ์ˆ˜ ์žˆ๋‚˜์š”?") +``` + +> [!TIP] +> ์—์ด์ „ํŠธ๋ฅผ ์ปจํ…์ŠคํŠธ ๊ด€๋ฆฌ์ž(`with` ๋ฌธ)๋กœ ์‚ฌ์šฉํ•˜๋ฉด ์—์ด์ „ํŠธ๊ฐ€ ์ž‘์—…์„ ์™„๋ฃŒํ•œ ์งํ›„ Docker ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ •๋ฆฌ๋˜๋„๋ก ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค. +> ๋˜๋Š” ์—์ด์ „ํŠธ์˜ `cleanup()` ๋ฉ”์†Œ๋“œ๋ฅผ ์ˆ˜๋™์œผ๋กœ ํ˜ธ์ถœํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. + +#### ๊ณ ๊ธ‰ Docker ์‚ฌ์šฉ๋ฒ•[[advanced-docker-usage]] + +Docker์—์„œ ๋‹ค์ค‘ ์—์ด์ „ํŠธ ์‹œ์Šคํ…œ์„ ์‹คํ–‰ํ•˜๋ ค๋ฉด ์ƒŒ๋“œ๋ฐ•์Šค์— ์‚ฌ์šฉ์ž ์ •์˜ ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. + +Dockerfile์„ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. + +```dockerfile +FROM python:3.10-bullseye + +# ๋นŒ๋“œ ์˜์กด์„ฑ ์„ค์น˜ +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + build-essential \ + python3-dev && \ + pip install --no-cache-dir --upgrade pip && \ + pip install --no-cache-dir smolagents && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +# ์ž‘์—… ๋””๋ ‰ํ„ฐ๋ฆฌ ์„ค์ • +WORKDIR /app + +# ์ œํ•œ๋œ ๊ถŒํ•œ์œผ๋กœ ์‹คํ–‰ +USER nobody + +# ๊ธฐ๋ณธ ๋ช…๋ น์–ด +CMD ["python", "-c", "print('Container ready')"] +``` + +์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ƒŒ๋“œ๋ฐ•์Šค ๊ด€๋ฆฌ์ž๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. + +```python +import docker +import os +from typing import Optional + +class DockerSandbox: + def __init__(self): + self.client = docker.from_env() + self.container = None + + def create_container(self): + try: + image, build_logs = self.client.images.build( + path=".", + tag="agent-sandbox", + rm=True, + forcerm=True, + buildargs={}, + # decode=True + ) + except docker.errors.BuildError as e: + print("Build error logs:") + for log in e.build_log: + if 'stream' in log: + print(log['stream'].strip()) + raise + + # ๋ณด์•ˆ ์ œ์•ฝ ์กฐ๊ฑด๊ณผ ์ ์ ˆํ•œ ๋กœ๊น…์œผ๋กœ ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ + self.container = self.client.containers.run( + "agent-sandbox", + command="tail -f /dev/null", # ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๊ณ„์† ์‹คํ–‰ ์ƒํƒœ๋กœ ์œ ์ง€ + detach=True, + tty=True, + mem_limit="512m", + cpu_quota=50000, + pids_limit=100, + security_opt=["no-new-privileges"], + cap_drop=["ALL"], + environment={ + "HF_TOKEN": os.getenv("HF_TOKEN") + }, + ) + + def run_code(self, code: str) -> Optional[str]: + if not self.container: + self.create_container() + + # ์ปจํ…Œ์ด๋„ˆ์—์„œ ์ฝ”๋“œ ์‹คํ–‰ + exec_result = self.container.exec_run( + cmd=["python", "-c", code], + user="nobody" + ) + + # ๋ชจ๋“  ์ถœ๋ ฅ ์ˆ˜์ง‘ + return exec_result.output.decode() if exec_result.output else None + + + def cleanup(self): + if self.container: + try: + self.container.stop() + except docker.errors.NotFound: + # ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ด๋ฏธ ์ œ๊ฑฐ๋จ, ์˜ˆ์ƒ๋œ ๋™์ž‘ + pass + except Exception as e: + print(f"Error during cleanup: {e}") + finally: + self.container = None # ์ฐธ์กฐ ์ œ๊ฑฐ + +# ์‚ฌ์šฉ ์˜ˆ์‹œ: +sandbox = DockerSandbox() + +try: + # ์—์ด์ „ํŠธ ์ฝ”๋“œ ์ •์˜ + agent_code = """ +import os +from smolagents import CodeAgent, InferenceClientModel + +# ์—์ด์ „ํŠธ ์ดˆ๊ธฐํ™” +agent = CodeAgent( + model=InferenceClientModel(token=os.getenv("HF_TOKEN"), provider="together"), + tools=[] +) + +# ์—์ด์ „ํŠธ ์‹คํ–‰ +response = agent.run("20๋ฒˆ์งธ ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜๋Š” ๋ฌด์—‡์ธ๊ฐ€์š”?") +print(response) +""" + + # ์ƒŒ๋“œ๋ฐ•์Šค์—์„œ ์ฝ”๋“œ ์‹คํ–‰ + output = sandbox.run_code(agent_code) + print(output) + +finally: + sandbox.cleanup() +``` + +### WebAssembly ์„ค์ •[[webassembly-setup]] + +WebAssembly(Wasm)๋Š” ์ฝ”๋“œ๋ฅผ ์•ˆ์ „ํ•œ ์ƒŒ๋“œ๋ฐ•์Šค ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋ฐ”์ด๋„ˆ๋ฆฌ ๋ช…๋ น์–ด ํ˜•์‹์ž…๋‹ˆ๋‹ค. +๋น ๋ฅด๊ณ  ํšจ์œจ์ ์ด๋ฉฐ ์•ˆ์ „ํ•˜๊ฒŒ ์„ค๊ณ„๋˜์–ด ์ž ์žฌ์ ์œผ๋กœ ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋ฐ ํƒ์›”ํ•œ ์„ ํƒ์ž…๋‹ˆ๋‹ค. + +`WasmExecutor`๋Š” [Pyodide](https://pyodide.org/)์™€ [Deno](https://docs.deno.com/)๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. + +#### ์„ค์น˜[[installation]] + +1. [์‹œ์Šคํ…œ์— Deno ์„ค์น˜ํ•˜๊ธฐ](https://docs.deno.com/runtime/getting_started/installation/) + +#### WebAssembly์—์„œ ์—์ด์ „ํŠธ ์‹คํ–‰ํ•˜๊ธฐ: ๋น ๋ฅธ ์‹œ์ž‘[[running-your-agent-in-webassembly-quick-start]] + +๋‹ค์Œ๊ณผ ๊ฐ™์ด ์—์ด์ „ํŠธ ์ดˆ๊ธฐํ™”์— `executor_type="wasm"`์„ ์ „๋‹ฌํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. +```py +from smolagents import InferenceClientModel, CodeAgent + +agent = CodeAgent(model=InferenceClientModel(), tools=[], executor_type="wasm") + +agent.run("100๋ฒˆ์งธ ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜๋ฅผ ์•Œ๋ ค์ค„ ์ˆ˜ ์žˆ๋‚˜์š”?") +``` + +### ์ƒŒ๋“œ๋ฐ•์Šค ๋ชจ๋ฒ” ์‚ฌ๋ก€[[best-practices-for-sandboxes]] + +์ด๋Ÿฌํ•œ ํ•ต์‹ฌ ์‚ฌ๋ก€๋Š” E2B์™€ Docker ์ƒŒ๋“œ๋ฐ•์Šค ๋ชจ๋‘์— ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. + +- ๋ฆฌ์†Œ์Šค ๊ด€๋ฆฌ + - ๋ฉ”๋ชจ๋ฆฌ ๋ฐ CPU ์ œํ•œ ์„ค์ • + - ์‹คํ–‰ ์‹œ๊ฐ„ ์ดˆ๊ณผ ๊ตฌํ˜„ + - ๋ฆฌ์†Œ์Šค ์‚ฌ์šฉ๋Ÿ‰ ๋ชจ๋‹ˆํ„ฐ๋ง +- ๋ณด์•ˆ + - ์ตœ์†Œํ•œ์˜ ๊ถŒํ•œ์œผ๋กœ ์‹คํ–‰ + - ๋ถˆํ•„์š”ํ•œ ๋„คํŠธ์›Œํฌ ์ ‘๊ทผ ๋น„ํ™œ์„ฑํ™” + - ๋น„๋ฐ€ ์ •๋ณด์— ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์‚ฌ์šฉ +- ํ™˜๊ฒฝ + - ์˜์กด์„ฑ์„ ์ตœ์†Œํ•œ์œผ๋กœ ์œ ์ง€ + - ๊ณ ์ •๋œ ํŒจํ‚ค์ง€ ๋ฒ„์ „ ์‚ฌ์šฉ + - ๊ธฐ๋ณธ ์ด๋ฏธ์ง€๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์ •๊ธฐ์ ์œผ๋กœ ์—…๋ฐ์ดํŠธ + +- ์ •๋ฆฌ + - ํŠนํžˆ Docker ์ปจํ…Œ์ด๋„ˆ์˜ ๊ฒฝ์šฐ, ๋ฆฌ์†Œ์Šค๋ฅผ ์žก์•„๋จน๋Š” ๋Œ€๋กฑ๊ฑฐ๋ฆฌ๋Š”(dangling) ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ƒ๊ธฐ์ง€ ์•Š๋„๋ก ํ•ญ์ƒ ์ ์ ˆํ•œ ๋ฆฌ์†Œ์Šค ์ •๋ฆฌ๋ฅผ ๋ณด์žฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. + +โœจ ์ด๋Ÿฌํ•œ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ๋”ฐ๋ฅด๊ณ  ์ ์ ˆํ•œ ์ •๋ฆฌ ์ ˆ์ฐจ๋ฅผ ๊ตฌํ˜„ํ•จ์œผ๋กœ์จ, ์—์ด์ „ํŠธ๊ฐ€ ์ƒŒ๋“œ๋ฐ•์Šค ํ™˜๊ฒฝ์—์„œ ์•ˆ์ „ํ•˜๊ณ  ํšจ์œจ์ ์œผ๋กœ ์‹คํ–‰๋˜๋„๋ก ๋ณด์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + +## ๋ณด์•ˆ ์ ‘๊ทผ ๋ฐฉ์‹ ๋น„๊ต[[comparing-security-approaches]] + +์•ž์„œ ๋‹ค์ด์–ด๊ทธ๋žจ์—์„œ ์„ค๋ช…ํ–ˆ๋“ฏ์ด, ๋‘ ์ƒŒ๋“œ๋ฐ•์‹ฑ ์ ‘๊ทผ ๋ฐฉ์‹์€ ์„œ๋กœ ๋‹ค๋ฅธ ๋ณด์•ˆ์  ์˜๋ฏธ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค. + +### ์ ‘๊ทผ ๋ฐฉ์‹ 1: ์ฝ”๋“œ ์Šค๋‹ˆํŽซ๋งŒ ์ƒŒ๋“œ๋ฐ•์Šค์—์„œ ์‹คํ–‰[[approach-1-running-just-the-code-snippets-in-a-sandbox]] +- **์žฅ์ **: + - ๊ฐ„๋‹จํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ(`executor_type="e2b"` ๋˜๋Š” `executor_type="docker"`)๋กœ ์„ค์ •ํ•˜๊ธฐ ๋” ์‰ฝ์Šต๋‹ˆ๋‹ค. + - API ํ‚ค๋ฅผ ์ƒŒ๋“œ๋ฐ•์Šค๋กœ ์ „์†กํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. + - ๋กœ์ปฌ ํ™˜๊ฒฝ์„ ๋” ์ž˜ ๋ณดํ˜ธํ•ฉ๋‹ˆ๋‹ค. +- **๋‹จ์ **: + - ๋‹ค์ค‘ ์—์ด์ „ํŠธ(๊ด€๋ฆฌํ˜• ์—์ด์ „ํŠธ)๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. + - ์—ฌ์ „ํžˆ ํ™˜๊ฒฝ๊ณผ ์ƒŒ๋“œ๋ฐ•์Šค ๊ฐ„์— ์ƒํƒœ๋ฅผ ์ „์†กํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. + - ํŠน์ • ์ฝ”๋“œ ์‹คํ–‰์— ์ œํ•œ๋ฉ๋‹ˆ๋‹ค. + +### ์ ‘๊ทผ ๋ฐฉ์‹ 2: ์ „์ฒด ์—์ด์ „ํŠธ ์‹œ์Šคํ…œ์„ ์ƒŒ๋“œ๋ฐ•์Šค์—์„œ ์‹คํ–‰[[approach-2-running-the-entire-agentic-system-in-a-sandbox]] +- **์žฅ์ **: + - ๋‹ค์ค‘ ์—์ด์ „ํŠธ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. + - ์ „์ฒด ์—์ด์ „ํŠธ ์‹œ์Šคํ…œ์„ ์™„๋ฒฝํ•˜๊ฒŒ ๊ฒฉ๋ฆฌํ•ฉ๋‹ˆ๋‹ค. + - ๋ณต์žกํ•œ ์—์ด์ „ํŠธ ์•„ํ‚คํ…์ฒ˜์— ๋” ์œ ์—ฐํ•ฉ๋‹ˆ๋‹ค. +- **๋‹จ์ **: + - ๋” ๋งŽ์€ ์ˆ˜๋™ ์„ค์ •์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. + - ๋ฏผ๊ฐํ•œ API ํ‚ค๋ฅผ ์ƒŒ๋“œ๋ฐ•์Šค๋กœ ์ „์†กํ•ด์•ผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + - ๋” ๋ณต์žกํ•œ ์ž‘์—…์œผ๋กœ ์ธํ•ด ์ž ์žฌ์ ์œผ๋กœ ๋” ๋†’์€ ์ง€์—ฐ ์‹œ๊ฐ„์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + +๋ณด์•ˆ ์š”๊ตฌ ์‚ฌํ•ญ๊ณผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์š”๊ตฌ ์‚ฌํ•ญ ์‚ฌ์ด์—์„œ ๊ฐ€์žฅ ๊ท ํ˜•์ด ์ž˜ ๋งž๋Š” ์ ‘๊ทผ ๋ฐฉ์‹์„ ์„ ํƒํ•˜์„ธ์š”. ๋” ๊ฐ„๋‹จํ•œ ์—์ด์ „ํŠธ ์•„ํ‚คํ…์ฒ˜๋ฅผ ๊ฐ€์ง„ ๋Œ€๋ถ€๋ถ„์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ฒฝ์šฐ, ์ ‘๊ทผ ๋ฐฉ์‹ 1์ด ๋ณด์•ˆ๊ณผ ์‚ฌ์šฉ ํŽธ์˜์„ฑ ์‚ฌ์ด์˜ ์ข‹์€ ๊ท ํ˜•์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์™„์ „ํ•œ ๊ฒฉ๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ๋” ๋ณต์žกํ•œ ๋‹ค์ค‘ ์—์ด์ „ํŠธ ์‹œ์Šคํ…œ์˜ ๊ฒฝ์šฐ, ์„ค์ •์ด ๋” ๋ณต์žกํ•˜์ง€๋งŒ ์ ‘๊ทผ ๋ฐฉ์‹ 2๊ฐ€ ๋” ๋‚˜์€ ๋ณด์•ˆ์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค. \ No newline at end of file