Pada tahun 2023, popularitas AI generatif akan menyebabkan semakin banyak organisasi memperkenalkan pengkodean yang dibantu AI. Yang sedikit berbeda dengan GitHub Copilot yang dirilis pada tahun 2021 adalah penyelesaian kode hanyalah salah satu dari banyak skenario. Sejumlah besar perusahaan sedang menjajaki skenario seperti menghasilkan kode lengkap dan tinjauan kode berdasarkan persyaratan, dan juga memperkenalkan AI generatif untuk meningkatkan efisiensi pengembangan.
Dalam konteks ini, kami (komunitas sumber terbuka Thoughtworks) juga telah menjadikan serangkaian alat tambahan AI sebagai sumber terbuka untuk membantu lebih banyak organisasi membangun asisten pengkodean berbantuan AI mereka sendiri:
Karena saat kami merancang AutoDev, berbagai model open source terus berkembang. Dalam konteks ini, langkah-langkahnya adalah:
Oleh karena itu, tutorial ini juga berpusat pada tiga langkah tersebut. Selain itu, berdasarkan pengalaman kami, contoh tumpukan teknologi untuk tutorial ini:
Karena pengalaman kami di bidang AI relatif terbatas, pasti akan ada beberapa kesalahan. Oleh karena itu, kami juga berharap dapat bekerja sama dengan lebih banyak pengembang untuk membangun proyek sumber terbuka ini.
Dikombinasikan dengan bagian kecerdasan buatan dalam laporan "Ekosistem Pengembang" JetBrains 2023, kami dapat merangkum beberapa skenario umum yang mencerminkan area di mana AI generatif dapat berperan dalam proses pengembangan. Berikut adalah beberapa skenario utama:
Saat kami membuat AutoDev, kami juga menemukan skenario seperti membuat SQL DDL, menghasilkan persyaratan, TDD, dll. Jadi. Kami memberikan kemampuan untuk menyesuaikan skenario sehingga pengembang dapat menyesuaikan kemampuan AI mereka sendiri. Untuk detailnya, lihat: https://ide.unitmesh.cc/customize.
Dalam pengkodean harian, ada beberapa skenario berbeda dengan persyaratan berbeda untuk kecepatan respons AI (sebagai contoh):
pemandangan | Kecepatan respons | Menghasilkan persyaratan kualitas | Ukuran yang diharapkan | menjelaskan |
---|---|---|---|---|
penyelesaian kode | cepat | tengah | 1~6B | Penyelesaian kode adalah skenario paling umum dalam pengkodean harian, dan kecepatan respons sangatlah penting. |
Pembuatan dokumen | tengah | tengah | 1 | Pembuatan dokumentasi memerlukan pemahaman penuh tentang struktur kode, dan kecepatan serta kualitas sama pentingnya. |
tinjauan kode | cepat | tengah | 1 | Peninjauan kode memerlukan saran berkualitas tinggi tetapi juga harus seresponsif mungkin. |
Pembuatan pengujian unit | cepat | tengah | 6B~ | Pengujian unit menghasilkan lebih sedikit konteks, dan daya tanggap serta kualitas AI sama pentingnya. |
pemfaktoran ulang kode | tengah | tinggi | 32B~ | Pemfaktoran ulang kode mungkin memerlukan pemahaman yang lebih kontekstual, dan waktu respons mungkin sedikit lebih lambat. |
pembangkitan permintaan | tengah | tinggi | 32B~ | Pembangkitan permintaan adalah skenario yang relatif kompleks, dan kecepatan respons dapat diperlambat untuk memastikan keakuratan. |
Pencarian dan interpretasi kode bahasa alami | Sedang-Rendah | tinggi | 32B~ | Pencarian dan interpretasi kode bahasa alami merupakan skenario yang relatif kompleks, dan kecepatan respons dapat diperlambat untuk memastikan keakuratan. |
PS: 32B disini hanya dinyatakan sebagai orde besarnya saja, karena pengaruhnya akan lebih baik dengan model yang lebih besar.
Oleh karena itu, kami meringkasnya sebagai: satu model besar, satu menengah, satu mikro, dan tiga model, yang menyediakan pengkodean komprehensif dengan bantuan AI:
Penyelesaian kode AI dapat menggabungkan alat IDE untuk menganalisis konteks kode dan aturan bahasa pemrograman, dan AI akan secara otomatis menghasilkan atau menyarankan cuplikan kode. Dalam alat penyelesaian kode yang mirip dengan GitHub Copilot, alat tersebut biasanya dibagi menjadi tiga mode subdivisi:
Penyelesaian sebaris (Sebaris)
Mirip dengan mode FIM (isi di tengah), konten yang sudah selesai ada di baris saat ini. Misalnya: BlotPost blogpost = new
, penyelesaiannya adalah: BlogPost();
untuk mencapai: BlogPost blogpost = new BlogPost();
Kita dapat menggunakan Deepseek Coder sebagai contoh untuk melihat efeknya dalam skenario ini:
< |fim▁begin| > def quick_sort(arr):
if len(arr) < = 1:
return arr
pivot = arr[0]
left = []
right = []
< |fim▁hole| >
if arr[i] < pivot:
left.append(arr[i])
else:
right.append(arr[i])
return quick_sort(left) + [pivot] + quick_sort(right) < |fim▁end| >
Di sini, kita perlu menggabungkan kode sebelum dan sesudah kursor.
Penyelesaian dalam blok (InBlock)
Dicapai melalui pembelajaran konteks (In-Context Learning), konten penyelesaian ada di blok fungsi saat ini. Misalnya kode aslinya adalah:
fun createBlog ( blogDto : CreateBlogDto ): BlogPost {
}
Kode yang lengkap adalah:
val blogPost = BlogPost (
title = blogDto.title,
content = blogDto.content,
author = blogDto.author
)
return blogRepository.save(blogPost)
Setelah Blokir
Dicapai melalui pembelajaran konteks (In-Context Learning), penyelesaian setelah blok fungsi saat ini, seperti: penyelesaian fungsi baru setelah blok fungsi saat ini. Misalnya kode aslinya adalah:
fun createBlog ( blogDto : CreateBlogDto ): BlogPost {
// ...
}
Kode yang lengkap adalah:
fun updateBlog ( id : Long , blogDto : CreateBlogDto ): BlogPost {
// ...
}
fun deleteBlog ( id : Long ) {
// ...
}
Saat kami membangun fungsi penyelesaian AI yang sesuai, kami juga perlu mempertimbangkan untuk menerapkannya pada kumpulan data pola yang sesuai untuk meningkatkan kualitas penyelesaian dan memberikan pengalaman pengguna yang lebih baik.
Beberapa sumber terkait untuk menulis artikel ini:
Penjelasan kode dirancang untuk membantu pengembang mengelola dan memahami basis kode besar dengan lebih efektif. Asisten ini dapat menjawab pertanyaan tentang basis kode, menyediakan dokumentasi, mencari kode, mengidentifikasi sumber kesalahan, mengurangi duplikasi kode, dll., sehingga meningkatkan efisiensi pengembangan, mengurangi tingkat kesalahan, dan mengurangi beban kerja pengembang.
Dalam skenario ini, bergantung pada kualitas generasi yang kita harapkan, biasanya terdiri dari dua model: satu model besar dan satu mikro atau satu model sedang dan satu mikro. Dikombinasikan dengan pengalaman desain kami pada alat Pabrik Coklat, biasanya fungsi seperti itu dapat dibagi menjadi beberapa langkah:
Sebagai aplikasi RAG, dibagi menjadi dua bagian: pengindeksan dan kueri.
Pada tahap pengindeksan, kita perlu mengindeks basis kode, yang melibatkan segmentasi teks, vektorisasi, pengindeksan basis data, dan teknologi lainnya. Salah satu elemen yang paling menantang adalah pemisahan. Aturan pemisahan yang kami rujuk adalah: https://docs.sweep.dev/blogs/chunking-2m-files. Sekarang:
Dalam skenario yang berbeda, kami juga dapat membagi dengan cara yang berbeda. Misalnya, di Pabrik Coklat, kami membagi melalui AST untuk memastikan kualitas konteks yang dihasilkan.
Pada tahap kueri, kita perlu menggabungkan beberapa teknologi penelusuran tradisional, seperti penelusuran vektorisasi, penelusuran jalur, dll., untuk memastikan kualitas penelusuran. Pada saat yang sama, dalam skenario bahasa Mandarin, kita juga perlu mempertimbangkan masalah konversi ke bahasa Mandarin, seperti mengonversi bahasa Inggris ke bahasa Mandarin untuk memastikan kualitas penelusuran.
Untuk bantuan sehari-hari, kita juga dapat mencapainya melalui AI generatif, seperti membuat SQL DDL secara otomatis, membuat kasus uji secara otomatis, membuat persyaratan secara otomatis, dll. Hal ini hanya dapat dicapai dengan menyesuaikan kata-kata cepat dan menggabungkan pengetahuan domain tertentu, jadi saya tidak akan membahas detailnya di sini.
Selain model, konteks juga menjadi faktor penting yang mempengaruhi kemampuan bantuan AI. Saat kami membuat AutoDev, kami juga menemukan dua mode konteks berbeda:
Perbandingan sederhananya adalah sebagai berikut:
konteks yang relevan | konteks serupa | |
---|---|---|
Teknologi pencarian | analisis kode statis | Pencarian kesamaan |
informasi struktur data | AST, CFG | Potongan serupa |
Kemampuan lintas platform | Tergantung pada IDE, atau parser independen | Tidak bergantung pada platform tertentu |
kualitas kontekstual | sangat tinggi | tinggi |
Hasilkan hasil | sangat tinggi | tinggi |
biaya pembangunan | Tergantung pada bahasa dan platform | Rendah |
Ketika dukungan untuk IDE terbatas, terkait konteks akan membawa kinerja biaya yang lebih tinggi.
GitHub Copilot mengadopsi pola arsitektur konteks serupa, dan arsitektur detailnya berlapis sebagai berikut:
Dalam materi penelitian proyek Copilot-Explorer "publik", Anda dapat melihat bagaimana Prompt dibuat. Berikut ini adalah permintaan cepat yang dikirim ke:
{
"prefix" : " # Path: codeviz \ app.py n #.... " ,
"suffix" : " if __name__ == '__main__': rn app.run(debug=True) " ,
"isFimEnabled" : true ,
"promptElementRanges" : [
{
"kind" : " PathMarker " ,
"start" : 0 ,
"end" : 23
},
{
"kind" : " SimilarFile " ,
"start" : 23 ,
"end" : 2219
},
{
"kind" : " BeforeCursor " ,
"start" : 2219 ,
"end" : 3142
}
]
}
di dalam:
prefix
yang digunakan untuk membuat prompt dibuat dari promptElements, yang meliputi: BeforeCursor
, AfterCursor
, SimilarFile
, ImportedFile
, LanguageMarker
, PathMarker
, RetrievalSnippet
dan tipe lainnya. Dari nama beberapa PromptElementKind
kita juga bisa melihat arti sebenarnya.suffix
yang digunakan untuk membuat prompt ditentukan oleh bagian dimana kursor berada. Menurut batas atas token (2048), berapa banyak posisi yang tersisa untuk dihitung. Perhitungan token di sini adalah perhitungan token LLM sebenarnya. Di Copilot, dihitung dengan Cushman002. Panjang token karakter Cina berbeda-beda, seperti: { context: "console.log('你好,世界')", lineCount: 1, tokenLength: 30 }
, dimana panjang konten dalam konteksnya adalah 20, tetapi tokenLength adalah 30, panjang karakter Cina adalah 5 (termasuk ,
), dan token yang ditempati oleh satu karakter adalah 3.Berikut adalah contoh konteks aplikasi Java yang lebih detail:
// Path: src/main/cc/unitmesh/demo/infrastructure/repositories/ProductRepository.java
// Compare this snippet from src/main/cc/unitmesh/demo/domain/product/Product.java:
// ....
// Compare this snippet from src/main/cc/unitmesh/demo/application/ProductService.java:
// ...
// @Component
// public class ProductService {
// //...
// }
//
package cc . unitmesh . demo . repositories ;
// ...
@ Component
public class ProductRepository {
//...
Dalam konteks komputasi, GitHub Copilot menggunakan koefisien Jaccard (Jaccard Kemiripan). Bagian implementasi ini diimplementasikan di Agen. Untuk logika lebih detail, silakan merujuk ke: Setelah menghabiskan lebih dari setengah bulan, saya akhirnya merekayasa balik Github Copilot.
Sumber daya terkait:
Seperti disebutkan di atas, kode yang relevan bergantung pada analisis kode statis , terutama dengan bantuan informasi struktural kode, seperti AST, CFG, DDG, dll. Dalam skenario dan platform yang berbeda, kita dapat menggabungkan alat analisis kode statis yang berbeda. Berikut ini adalah beberapa alat analisis kode statis yang umum:
Dalam skenario penyelesaian, melalui analisis kode statis, kita bisa mendapatkan konteks saat ini, seperti: fungsi saat ini, kelas saat ini, file saat ini, dll. Berikut ini adalah contoh konteks AutoDev untuk menghasilkan pengujian unit:
// here are related classes:
// 'filePath: /Users/phodal/IdeaProjects/untitled/src/main/java/cc/unitmesh/untitled/demo/service/BlogService.java
// class BlogService {
// blogRepository
// + public BlogPost createBlog(BlogPost blogDto)
// + public BlogPost getBlogById(Long id)
// + public BlogPost updateBlog(Long id, BlogPost blogDto)
// + public void deleteBlog(Long id)
// }
// 'filePath: /Users/phodal/IdeaProjects/untitled/src/main/java/cc/unitmesh/untitled/demo/dto/CreateBlogRequest.java
// class CreateBlogRequest ...
// 'filePath: /Users/phodal/IdeaProjects/untitled/src/main/java/cc/unitmesh/untitled/demo/entity/BlogPost.java
// class BlogPost {...
@ ApiOperation ( value = "Create a new blog" )
@ PostMapping ( "/" )
public BlogPost createBlog ( @ RequestBody CreateBlogRequest request ) {
Dalam contoh ini, konteks fungsi createBlog
dianalisis untuk mendapatkan kelas input dan output fungsi: CreateBlogRequest
, informasi BlogPost
, dan informasi kelas BlogService, yang diberikan kepada model sebagai konteks (disediakan dalam komentar). Pada titik ini, model menghasilkan konstruktor yang lebih akurat, serta kasus pengujian yang lebih akurat.
Karena konteks yang relevan bergantung pada analisis kode statis dari berbagai bahasa dan API dari IDE yang berbeda, kita juga perlu beradaptasi dengan bahasa yang berbeda dan IDE yang berbeda. Dalam hal biaya konstruksi, ini lebih mahal dibandingkan dengan konteks serupa.
IDE dan editor adalah alat utama bagi pengembang, dan biaya desain serta pembelajarannya relatif tinggi. Pertama, kita dapat menggunakan template resmi untuk menghasilkan:
Lalu, menambahkan fungsionalitas di atas (sederhana sekali bukan), tentu saja tidak. Berikut ini adalah beberapa sumber plug-in IDEA untuk referensi:
Tentu saja lebih tepat merujuk pada plugin AutoDev.
Anda dapat langsung menggunakan templat resmi untuk membuat plugin yang sesuai: https://github.com/JetBrains/intellij-platform-plugin-template
Untuk implementasi plug-in IDEA, ini terutama diimplementasikan melalui Action dan Listener, yang hanya perlu didaftarkan di plugin.xml
. Untuk detailnya, silakan merujuk ke dokumentasi resmi: IntelliJ Platform Plugin SDK
Karena kami tidak mempertimbangkan masalah kompatibilitas dengan AutoDev versi IDE pada tahap awal, agar kompatibel dengan IDE versi lama nanti, kami perlu melakukan pemrosesan kompatibilitas pada plug-in. Oleh karena itu, seperti yang dijelaskan dalam dokumen resmi: Build Number Ranges, kita dapat melihat bahwa versi yang berbeda memiliki persyaratan yang berbeda untuk JDK. Berikut ini adalah persyaratan untuk versi yang berbeda:
Nomor cabang | Versi Platform IntelliJ |
---|---|
233 | 2023.3 |
232 | 2023.2 |
231 | 2023.1 |
223 | 2022.3 |
222 | 2022.2 CATATAN Java 17 sekarang diperlukan (postingan blog) |
221 | 2022.1 |
213 | 2021.3 |
212 | 2021.2 |
211 | 2021.1 |
203 | 2020.3 CATATAN Java 11 sekarang diperlukan (postingan blog) |
Dan konfigurasikan menjadi gradle.properties
:
pluginSinceBuild = 223
pluginUntilBuild = 233.*
Konfigurasi kompatibilitas selanjutnya merepotkan, jadi Anda bisa merujuk pada desain AutoDev.
Dalam hal penyelesaian kode otomatis, pabrikan dalam negeri terutama mengacu pada implementasi GitHub Copilot, dan logikanya tidak rumit.
Pemicu menggunakan tombol pintas
Ini terutama memonitor input pengguna dalam Action, dan kemudian:
Fungsi | tombol pintas | menjelaskan |
---|---|---|
permintaan Penyelesaian | Alt + / | Dapatkan konteks saat ini dan kemudian dapatkan hasil penyelesaian melalui model |
terapkanInlay | TAB | Menampilkan hasil penyelesaian pada IDE |
buangInlays | ESC | Batalkan penyelesaian |
cycleNextInlays | Alt + ] | Beralih ke hasil penyelesaian berikutnya |
cyclePrevInlays | Alt + [ | Beralih ke hasil penyelesaian sebelumnya |
Gunakan metode pemicuan otomatis
Ini terutama memantau masukan pengguna melalui EditorFactoryListener
, dan kemudian memicu hasil penyelesaian yang berbeda berdasarkan masukan yang berbeda. Kode intinya adalah sebagai berikut:
class AutoDevEditorListener : EditorFactoryListener {
override fun editorCreated ( event : EditorFactoryEvent ) {
// ...
editor.document.addDocumentListener( AutoDevDocumentListener (editor), editorDisposable)
editor.caretModel.addCaretListener( AutoDevCaretListener (editor), editorDisposable)
// ...
}
class AutoDevCaretListener ( val editor : Editor ) : CaretListener {
override fun caretPositionChanged ( event : CaretEvent ) {
// ...
val wasTypeOver = TypeOverHandler .getPendingTypeOverAndReset(editor)
// ...
llmInlayManager.disposeInlays(editor, InlayDisposeContext . CaretChange )
}
}
class AutoDevDocumentListener ( val editor : Editor ) : BulkAwareDocumentListener {
override fun documentChangedNonBulk ( event : DocumentEvent ) {
// ...
val llmInlayManager = LLMInlayManager .getInstance()
llmInlayManager
.editorModified(editor, changeOffset)
}
}
}
Kemudian berdasarkan masukan yang berbeda, hasil penyelesaian yang berbeda dipicu dan struktur diproses.
Kode penyelesaian render
Selanjutnya, kita perlu mengimplementasikan Inlay Render, yang mewarisi dari EditorCustomElementRenderer
.
Dikombinasikan dengan kemampuan antarmuka IDE, kita perlu menambahkan Action yang sesuai, Group yang sesuai, dan Icon yang sesuai. Berikut contoh Aksinya:
<add-to-group group-id="ShowIntentionsGroup" relative-to-action="ShowIntentionActions" anchor="after"/>
Berikut ini adalah beberapa ActionGroup dari AutoDev:
ID Grup | penggunaan AI | Keterangan |
---|---|---|
Tampilkan Grup Niat | Pemfaktoran ulang kode, interpretasi kode, pembuatan kode, pengujian kode | Digunakan untuk menampilkan petunjuk dalam konteks kode dan diakses melalui pintasan Alt + Enter dan ⌥ + Enter di macOS. |
Menu PopupEditor Konsol | memperbaiki kesalahan | Menu yang ditampilkan di konsol, seperti konsol struktur eksekusi program. |
Vcs.MessageActionGroup | Pembuatan informasi kode | Menu untuk menulis pesan komit di VCS. |
Vcs.Log.ContextMenu | Tinjauan kode, interpretasi kode, pembuatan kode | Menu untuk melihat log di VCS, fungsi yang tersedia: Inspeksi kode AI, pembuatan log rilis. |
EditorPopupMenu | Semuanya bisa diterima | Menu klik kanan, Anda juga dapat menambahkan ActionGroup yang sesuai |
Saat menulis ShowIntentionsGroup, kita dapat merujuk pada implementasi AutoDev untuk membangun Grup yang sesuai:
< group id = " AutoDevIntentionsActionGroup " class = " cc.unitmesh.devti.intentions.IntentionsActionGroup "
icon = " cc.unitmesh.devti.AutoDevIcons.AI_COPILOT " searchable = " false " >
< add-to-group group-id = " ShowIntentionsGroup " relative-to-action = " ShowIntentionActions " anchor = " after " />
</ group >
Karena strategi platform Intellij, perbedaan antara berjalan di Java IDE (Intellij IDEA) dan IDE lain seperti Python IDE (Pycharm) menjadi lebih besar. Kami perlu menyediakan kompatibilitas berdasarkan produk multi-platform. Untuk pengenalan mendetail, silakan merujuk ke: Kompatibilitas Plugin dengan Produk Platform IntelliJ
Pertama, arsitektur plug-in dimodulasi lebih lanjut, yaitu modul berbeda disediakan untuk bahasa berbeda. Berikut ini adalah arsitektur modular AutoDev:
java/ # Java 语言插件
src/main/java/cc/unitmesh/autodev/ # Java 语言入口
src/main/resources/META-INF/plugin.xml
plugin/ # 多平台入口
src/main/resources/META-INF/plugin.xml
src/ # 即核心模块
main/resource/META-INF/core.plugin.xml
Di plugin/plugin.xml
, kita perlu menambahkan depends
dan extensions
yang sesuai. Berikut ini contohnya:
< idea-plugin package = " cc.unitmesh " xmlns : xi = " http://www.w3.org/2001/XInclude " allow-bundled-update = " true " >
< xi : include href = " /META-INF/core.xml " xpointer = " xpointer(/idea-plugin/*) " />
< content >
< module name = " cc.unitmesh.java " />
<!-- 其它模块 -->
</ content >
</ idea-plugin >
Di java/plugin.xml
, kita perlu menambahkan depends
dan extensions
yang sesuai. Berikut ini contohnya:
< idea-plugin package = " cc.unitmesh.java " >
<!-- suppress PluginXmlValidity -->
< dependencies >
< plugin id = " com.intellij.modules.java " />
< plugin id = " org.jetbrains.plugins.gradle " />
</ dependencies >
</ idea-plugin >
Selanjutnya, Intellij akan secara otomatis memuat modul yang sesuai untuk mencapai dukungan multi-bahasa. Bergantung pada bahasa berbeda yang kami harapkan untuk didukung, kami memerlukan plugin.xml
yang sesuai, seperti:
cc.unitmesh.javascript.xml
cc.unitmesh.rust.xml
cc.unitmesh.python.xml
cc.unitmesh.kotlin.xml
cc.unitmesh.java.xml
cc.unitmesh.go.xml
cc.unitmesh.cpp.xml
Terakhir, implementasikan saja fungsi terkait dalam modul bahasa yang berbeda.
Untuk menyederhanakan proses ini, kami menggunakan Unit Eval untuk menunjukkan cara membangun dua konteks serupa.
Melalui analisis kode statis, kita bisa mendapatkan fungsi saat ini, kelas saat ini, file saat ini, dll. Kemudian gabungkan kesamaan jalur untuk menemukan konteks yang paling relevan.
private fun findRelatedCode ( container : CodeContainer ): List < CodeDataStruct > {
// 1. collects all similar data structure by imports if exists in a file tree
val byImports = container. Imports
.mapNotNull {
context.fileTree[it. Source ]?.container?. DataStructures
}
.flatten()
// 2. collects by inheritance tree for some node in the same package
val byInheritance = container. DataStructures
.map {
(it. Implements + it. Extend ).mapNotNull { i ->
context.fileTree[i]?.container?. DataStructures
}.flatten()
}
.flatten()
val related = (byImports + byInheritance).distinctBy { it. NodeName }
// 3. convert all similar data structure to uml
return related
}
class RelatedCodeStrategyBuilder ( private val context : JobContext ) : CodeStrategyBuilder {
override fun build (): List < TypedIns > {
// ...
val findRelatedCodeDs = findRelatedCode(container)
val relatedCodePath = findRelatedCodeDs.map { it. FilePath }
val jaccardSimilarity = SimilarChunker .pathLevelJaccardSimilarity(relatedCodePath, currentPath)
val relatedCode = jaccardSimilarity.mapIndexed { index, d ->
findRelatedCodeDs[index] to d
}.sortedByDescending {
it.second
}.take( 3 ).map {
it.first
}
// ...
}
}
Untuk kode di atas, kita dapat menggunakan informasi Impor kode tersebut sebagai bagian dari kode yang relevan. Kemudian temukan kode yang relevan melalui hubungan pewarisan kode tersebut. Terakhir, konteks terdekat ditemukan melalui kesamaan jalur.
Cari dulu, lalu temukan kode terkait melalui kesamaan kode. Logika inti ditampilkan:
fun pathLevelJaccardSimilarity ( chunks : List < String >, text : String ): List < Double > {
// ...
}
fun tokenize ( chunk : String ): List < String > {
return chunk.split( Regex ( " [^a-zA-Z0-9] " )).filter { it.isNotBlank() }
}
fun similarityScore ( set1 : Set < String >, set2 : Set < String >): Double {
// ...
}
Untuk detailnya, lihat: MiripChunker
TODO
TreeSitter adalah kerangka kerja untuk menghasilkan parser khusus yang efisien, yang dikembangkan oleh GitHub. Ia menggunakan parser LR(1), yang berarti ia dapat mengurai bahasa apa pun dalam waktu O(n), bukan waktu O(n²). Ia juga menggunakan teknik yang disebut "penggunaan kembali pohon sintaksis" yang memungkinkannya memperbarui pohon sintaksis tanpa menguraikan ulang seluruh file.
Karena TreeSitter sudah menyediakan dukungan multi-bahasa, Anda dapat menggunakan Node.js, Rust, dan bahasa lain untuk membuat plugin yang sesuai. Lihat: TreeSitter untuk detailnya.
Tergantung pada niat kita, ada berbagai cara untuk menggunakan TreeSitter:
Mengurai Simbol
Dalam kode mesin pencari bahasa alami Bloop, kami menggunakan TreeSitter untuk mengurai Simbol guna mencapai kualitas pencarian yang lebih baik.
; ; methods
(method_declaration
name: (identifier) @hoist.definition.method)
Kemudian, tentukan cara menampilkannya berdasarkan jenisnya:
pub static JAVA : TSLanguageConfig = TSLanguageConfig {
language_ids : & [ "Java" ] ,
file_extensions : & [ "java" ] ,
grammar : tree_sitter_java :: language ,
scope_query : MemoizedQuery :: new ( include_str ! ( "./scopes.scm" ) ) ,
hoverable_query : MemoizedQuery :: new (
r#"
[(identifier)
(type_identifier)] @hoverable
"# ,
) ,
namespaces : & [ & [
// variables
"local" ,
// functions
"method" ,
// namespacing, modules
"package" ,
"module" ,
// types
"class" ,
"enum" ,
"enumConstant" ,
"record" ,
"interface" ,
"typedef" ,
// misc.
"label" ,
] ] ,
} ;
Kode potongan
Berikut adalah cara TreeSitter digunakan dalam Meningkatkan Potongan Kode LlamaIndex dengan Membersihkan CST Tree-Sitter:
from tree_sitter import Tree
def chunker (
tree : Tree ,
source_code : bytes ,
MAX_CHARS = 512 * 3 ,
coalesce = 50 # Any chunk less than 50 characters long gets coalesced with the next chunk
) -> list [ Span ]:
# 1. Recursively form chunks based on the last post (https://docs.sweep.dev/blogs/chunking-2m-files)
def chunk_node ( node : Node ) -> list [ Span ]:
chunks : list [ Span ] = []
current_chunk : Span = Span ( node . start_byte , node . start_byte )
node_children = node . children
for child in node_children :
if child . end_byte - child . start_byte > MAX_CHARS :
chunks . append ( current_chunk )
current_chunk = Span ( child . end_byte , child . end_byte )
chunks . extend ( chunk_node ( child ))
elif child . end_byte - child . start_byte + len ( current_chunk ) > MAX_CHARS :
chunks . append ( current_chunk )
current_chunk = Span ( child . start_byte , child . end_byte )
else :
current_chunk += Span ( child . start_byte , child . end_byte )
chunks . append ( current_chunk )
return chunks
chunks = chunk_node ( tree . root_node )
# 2. Filling in the gaps
for prev , curr in zip ( chunks [: - 1 ], chunks [ 1 :]):
prev . end = curr . start
curr . start = tree . root_node . end_byte
# 3. Combining small chunks with bigger ones
new_chunks = []
current_chunk = Span ( 0 , 0 )
for chunk in chunks :
current_chunk += chunk
if non_whitespace_len ( current_chunk . extract ( source_code )) > coalesce